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>
14244 lines
568 KiB
PL/PgSQL
14244 lines
568 KiB
PL/PgSQL
-- All routines in dune schema, concatenated. Generated by _export.sh
|
|
|
|
-- _add_item_delete_log(in_item_id bigint, in_inventory_id bigint, in_template_id text) -> void
|
|
-- oid: 58085 kind: FUNCTION category: player_persistence
|
|
|
|
CREATE OR REPLACE FUNCTION dune._add_item_delete_log(in_item_id bigint, in_inventory_id bigint, in_template_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM _add_item_trace_log('delete_item', in_item_id, in_inventory_id, in_template_id);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- _add_item_trace_log(in_function_name dune.itemtrackingfunctiontype, in_item_locations dune.inventoryitemlocation[]) -> void
|
|
-- oid: 58086 kind: FUNCTION category: player_persistence
|
|
|
|
CREATE OR REPLACE FUNCTION dune._add_item_trace_log(in_function_name dune.itemtrackingfunctiontype, in_item_locations dune.inventoryitemlocation[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF coalesce(current_setting('dune.item_tracking_enabled', true)::BOOLEAN, false) IS FALSE THEN
|
|
return;
|
|
END IF;
|
|
|
|
INSERT INTO item_operations_staging_table (
|
|
function_name,
|
|
item_id,
|
|
account_id,
|
|
inventory_id,
|
|
template_id,
|
|
event_time,
|
|
position_index
|
|
)
|
|
SELECT
|
|
in_function_name,
|
|
(loc).item_id,
|
|
act.owner_account_id,
|
|
(loc).inventory_id,
|
|
NULL, -- template_id
|
|
now(),
|
|
(loc).position_index
|
|
FROM UNNEST(in_item_locations) AS loc
|
|
JOIN inventories inv ON inv.id = (loc).inventory_id
|
|
JOIN actors act ON act.id = inv.actor_id;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- _add_item_trace_log(in_function_name dune.itemtrackingfunctiontype, in_item_id bigint, in_inventory_id bigint, in_template_id text, in_position_index bigint) -> void
|
|
-- oid: 58087 kind: FUNCTION category: player_persistence
|
|
|
|
CREATE OR REPLACE FUNCTION dune._add_item_trace_log(in_function_name dune.itemtrackingfunctiontype, in_item_id bigint, in_inventory_id bigint, in_template_id text, in_position_index bigint DEFAULT NULL::bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
owner_account_id BIGINT;
|
|
BEGIN
|
|
IF coalesce(current_setting('dune.item_tracking_enabled', true)::BOOLEAN, false) IS FALSE THEN
|
|
return;
|
|
END IF;
|
|
|
|
-- get item owner's account id
|
|
SELECT act.owner_account_id
|
|
INTO owner_account_id
|
|
FROM inventories inv
|
|
JOIN actors act ON act.id = inv.actor_id
|
|
WHERE inv.id = in_inventory_id;
|
|
|
|
INSERT INTO item_operations_staging_table (
|
|
function_name,
|
|
item_id,
|
|
account_id,
|
|
inventory_id,
|
|
template_id,
|
|
event_time,
|
|
position_index
|
|
) VALUES (
|
|
in_function_name,
|
|
in_item_id,
|
|
owner_account_id,
|
|
in_inventory_id,
|
|
in_template_id,
|
|
now(),
|
|
in_position_index
|
|
);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- _building_validate_totem_owner_id(in_totem_owner_id bigint) -> bigint
|
|
-- oid: 58094 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune._building_validate_totem_owner_id(in_totem_owner_id bigint)
|
|
RETURNS bigint
|
|
LANGUAGE sql
|
|
BEGIN ATOMIC
|
|
SELECT
|
|
CASE
|
|
WHEN (in_totem_owner_id = 0) THEN NULL::bigint
|
|
WHEN (EXISTS ( SELECT 1
|
|
FROM dune.fgl_entities
|
|
WHERE (fgl_entities.entity_id = _building_validate_totem_owner_id.in_totem_owner_id))) THEN in_totem_owner_id
|
|
ELSE NULL::bigint
|
|
END AS "case";
|
|
END
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _character_transfer_ensure_player_is_owner_of_vbt_vehicle(in_vehicle_id bigint[]) -> void
|
|
-- oid: 58100 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune._character_transfer_ensure_player_is_owner_of_vbt_vehicle(in_vehicle_id bigint[])
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
update permission_actor_rank set "rank" = 1 where permission_actor_id = any(in_vehicle_id);
|
|
$function$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _character_transfer_store_in_world_owned_vehicles_into_recovery(in_player_id bigint) -> void
|
|
-- oid: 58109 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune._character_transfer_store_in_world_owned_vehicles_into_recovery(in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
to_store RECORD;
|
|
BEGIN
|
|
-- remove any vehicles in 'Travel' state, so that they get re-added as recovered vehicles
|
|
DELETE FROM actor_state ast
|
|
WHERE ast.state = 'Travel'
|
|
AND ast.actor_id IN (
|
|
SELECT v.id
|
|
FROM actors a
|
|
INNER JOIN vehicles v ON a.id = v.id
|
|
INNER JOIN permission_actor p ON a.id = p.actor_id
|
|
INNER JOIN permission_actor_rank r ON p.actor_id = r.permission_actor_id
|
|
WHERE r.player_id = in_player_id
|
|
AND r.rank = 1::smallint
|
|
);
|
|
|
|
FOR to_store IN
|
|
SELECT v.id AS vehicle_id
|
|
FROM actors a
|
|
INNER JOIN vehicles v ON a.id = v.id
|
|
INNER JOIN permission_actor p ON a.id = p.actor_id
|
|
INNER JOIN permission_actor_rank r ON p.actor_id = r.permission_actor_id
|
|
WHERE r.player_id = in_player_id
|
|
AND r.rank = 1::smallint
|
|
AND NOT EXISTS
|
|
(
|
|
SELECT 1 FROM actor_state
|
|
WHERE actor_state.actor_id = v.id
|
|
AND actor_state.state IS DISTINCT FROM 'Default'
|
|
)
|
|
LOOP
|
|
-- note: storing hardcoded chassis durability because its not available from pure database :(
|
|
-- this will only be shown incorrectly in UI though, the spawned vehicle will get the correct value
|
|
PERFORM store_recovered_vehicle(to_store.vehicle_id, 1.0, 'None', true);
|
|
|
|
-- we delete the permissions for this vehicle so that they don't get exported and cause duplicated key failures
|
|
-- when the player tries to recover their vehicle on the target battlegroup
|
|
-- note: the server will destroy the vehicle as soon as it gets the pg_notify emitted from the store_recovered_vehicle call above, so this would happen regardless
|
|
DELETE FROM permission_actor pa WHERE pa.actor_id = to_store.vehicle_id;
|
|
END LOOP;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _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$
|
|
|
|
|
|
-- _placeable_validate_totem_owner_id(in_totem_owner_id bigint) -> bigint
|
|
-- oid: 58112 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune._placeable_validate_totem_owner_id(in_totem_owner_id bigint)
|
|
RETURNS bigint
|
|
LANGUAGE sql
|
|
BEGIN ATOMIC
|
|
SELECT
|
|
CASE
|
|
WHEN (in_totem_owner_id = 0) THEN NULL::bigint
|
|
WHEN (EXISTS ( SELECT 1
|
|
FROM dune.fgl_entities
|
|
WHERE (fgl_entities.entity_id = _placeable_validate_totem_owner_id.in_totem_owner_id))) THEN in_totem_owner_id
|
|
ELSE NULL::bigint
|
|
END AS "case";
|
|
END
|
|
|
|
|
|
-- _user_data_encryption_initially_encrypt_existing_data() -> void
|
|
-- oid: 58113 kind: FUNCTION category: encryption
|
|
|
|
CREATE OR REPLACE FUNCTION dune._user_data_encryption_initially_encrypt_existing_data()
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
update encrypted_accounts set encrypted_funcom_id=encrypt_user_data(convert_from(encrypted_funcom_id, 'utf8'));
|
|
update encrypted_player_state set
|
|
encrypted_character_name=encrypt_user_data(convert_from(encrypted_character_name, 'utf8'));
|
|
$function$
|
|
|
|
|
|
-- _user_data_encryption_setup_enabled(key_hash bytea) -> void
|
|
-- oid: 58114 kind: FUNCTION category: encryption
|
|
|
|
CREATE OR REPLACE FUNCTION dune._user_data_encryption_setup_enabled(key_hash bytea)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
if key_hash is null then
|
|
raise exception 'User-data encryption requested but the server does not have the encryption key set';
|
|
end if;
|
|
|
|
if (select get_stored_user_data_encryption_taint_xmax()) is not null then
|
|
-- should have been filtered by the main setup function
|
|
raise exception 'Trying to enable encryption on a tainted data';
|
|
end if;
|
|
|
|
execute format($x$
|
|
create or replace function get_stored_user_data_encryption_key_hash() returns bytea immutable
|
|
as $y$select '%s'::bytea;$y$ language sql;
|
|
$x$, key_hash::text);
|
|
|
|
-- the data is encrypted and we have the key
|
|
create or replace function get_stored_user_data_encryption_status() returns UserDataEncryptionStatus immutable
|
|
as $x$select 'Enabled'::UserDataEncryptionStatus;$x$ language sql;
|
|
|
|
-- We may bake the key into the function code but then dumping the functions will reveal the key
|
|
create or replace function encrypt_user_data(in_data text) returns bytea immutable as $x$
|
|
select ext.encrypt(convert_to(in_data, 'utf8'), current_setting('funcom.user_data_encryption_key')::bytea, 'aes')::bytea;
|
|
$x$ language sql;
|
|
|
|
create or replace function decrypt_user_data(in_encrypted_data bytea) returns text immutable as $x$
|
|
select convert_from(
|
|
ext.decrypt(in_encrypted_data, current_setting('funcom.user_data_encryption_key')::bytea, 'aes'), 'utf8'
|
|
);
|
|
$x$ language sql;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- _user_data_encryption_setup_tainted() -> void
|
|
-- oid: 58115 kind: FUNCTION category: encryption
|
|
|
|
CREATE OR REPLACE FUNCTION dune._user_data_encryption_setup_tainted()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
-- we not replacing get_stored_user_data_encryption_key_hash()
|
|
if (select get_stored_user_data_encryption_key_hash()) is null then
|
|
-- should have been filtered by the main setup function
|
|
raise exception 'Tainted but the data is not encrypted in the first place';
|
|
end if;
|
|
|
|
execute format($x$
|
|
create or replace function get_stored_user_data_encryption_taint_xmax() returns int8 immutable
|
|
as 'select %s;' language sql;
|
|
$x$, pg_current_xact_id());
|
|
|
|
-- the data is encrypted but we don't have the key (or don't want to)
|
|
create or replace function get_stored_user_data_encryption_status() returns UserDataEncryptionStatus immutable
|
|
as $x$select 'Tainted'::UserDataEncryptionStatus;$x$ language sql;
|
|
|
|
create or replace function encrypt_user_data(in_data text) returns bytea immutable
|
|
as $x$select convert_to(in_data, 'utf8')$x$ language sql;
|
|
|
|
-- We may use the taint xmax to differentiate between encrypted/unencrypted data for that we would have to pass the
|
|
-- xmin into the function (which is xid and not xid8)
|
|
create or replace function decrypt_user_data(in_encrypted_data bytea) returns text immutable
|
|
as $x$select encode(in_encrypted_data, 'hex');$x$ language sql;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- accept_guild_invite(in_invite_id bigint, in_role_id smallint, in_max_guild_count_per_player integer, in_max_members_per_guild integer, in_neutral_faction_id smallint) -> void
|
|
-- oid: 58116 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.accept_guild_invite(in_invite_id bigint, in_role_id smallint, in_max_guild_count_per_player integer, in_max_members_per_guild integer, in_neutral_faction_id smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
member_count INTEGER := 0;
|
|
player_id BIGINT := 0;
|
|
found_guild_id BIGINT := 0;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- check if invite exists
|
|
SELECT guild_invites.player_id, guild_invites.guild_id FROM guild_invites WHERE invite_id = in_invite_id INTO player_id, found_guild_id;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trying to accept non exiting invite %.', in_invite_id;
|
|
END IF;
|
|
|
|
-- delete invite
|
|
DELETE FROM guild_invites WHERE invite_id = in_invite_id;
|
|
|
|
SELECT INTO member_count COUNT(*) FROM guild_members where guild_members.guild_id = found_guild_id;
|
|
|
|
-- check if we've reached guild member limit
|
|
IF member_count >= in_max_members_per_guild THEN
|
|
RAISE EXCEPTION 'Cannot insert more than % members per guild.', in_max_members_per_guild;
|
|
END IF;
|
|
|
|
-- add member
|
|
PERFORM add_guild_member(player_id, found_guild_id, in_role_id, in_max_guild_count_per_player, in_max_members_per_guild, in_neutral_faction_id);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- accept_party_invite(in_invite_id bigint, in_platform_session_id text, in_max_party_member_count integer) -> dune.partyacceptinviteresult
|
|
-- oid: 58117 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.accept_party_invite(in_invite_id bigint, in_platform_session_id text, in_max_party_member_count integer)
|
|
RETURNS dune.partyacceptinviteresult
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_player_id BIGINT;
|
|
out_sender_id BIGINT;
|
|
out_party_id BIGINT;
|
|
out_player_platform_name TEXT;
|
|
out_player_platform_id TEXT;
|
|
out_sender_platform_name TEXT;
|
|
out_sender_platform_session_id TEXT;
|
|
out_accept_error PartyAcceptInviteResult DEFAULT 'Success'::PartyAcceptInviteResult;
|
|
BEGIN
|
|
PERFORM parties_get_exclusive_operation_lock();
|
|
|
|
-- check if invite exists
|
|
SELECT party_id, player_id, sender_player_id, sender_platform_name, sender_platform_session_id FROM party_invites
|
|
WHERE invite_id = in_invite_id INTO out_party_id, out_player_id, out_sender_id, out_sender_platform_name, out_sender_platform_session_id;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trying to accept non exiting party invite %.', in_invite_id;
|
|
out_accept_error = 'NonExistingInvite'::PartyAcceptInviteResult;
|
|
END IF;
|
|
|
|
-- query receiver platform data
|
|
SELECT acc.platform_name, acc.platform_id INTO out_player_platform_name, out_player_platform_id
|
|
FROM accounts acc LEFT JOIN player_state ps ON acc.id=ps.account_id
|
|
WHERE ps.player_controller_id = out_player_id;
|
|
|
|
IF out_party_id IS NULL THEN
|
|
PERFORM internal_create_party(in_invite_id, out_sender_id, out_sender_platform_session_id, out_sender_platform_name,
|
|
out_player_id, in_platform_session_id, out_player_platform_name);
|
|
ELSE
|
|
out_accept_error := internal_add_party_member(in_invite_id, out_party_id, out_player_id, in_platform_session_id, out_player_platform_name, in_max_party_member_count);
|
|
END IF;
|
|
|
|
-- Delete any sent or reiceived invites from the player who's accepting the invitation
|
|
DELETE FROM party_invites WHERE sender_player_id = out_player_id OR player_id = out_player_id;
|
|
RETURN out_accept_error;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- add_actor_audit(in_id bigint, in_class text) -> void
|
|
-- oid: 58118 kind: FUNCTION category: anticheat
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_actor_audit(in_id bigint, in_class text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO actor_audit("id", "class") VALUES(in_id, in_class) ON CONFLICT(id) DO NOTHING;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- add_event_log_data(in_game_event_owner bigint, in_universe_time bigint, in_map_name text, in_partition_id bigint, in_event_type integer, in_x_location double precision, in_y_location double precision, in_z_location double precision, in_is_player_facing boolean, in_custom_data text) -> void
|
|
-- oid: 58119 kind: FUNCTION category: event_log
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_event_log_data(in_game_event_owner bigint, in_universe_time bigint, in_map_name text, in_partition_id bigint, in_event_type integer, in_x_location double precision, in_y_location double precision, in_z_location double precision, in_is_player_facing boolean, in_custom_data text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO game_events(actor_id, universe_time, map, partition_id, event_type, x, y, z, custom_data, player_facing_event) VALUES(in_game_event_owner, to_timestamp(in_universe_time), in_map_name, in_partition_id, in_event_type, in_x_location, in_y_location, in_z_location, in_custom_data::JsonB, in_is_player_facing);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- add_event_log_data_batched(in_data dune.eventlogbulkentrydata[]) -> void
|
|
-- oid: 58120 kind: FUNCTION category: event_log
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_event_log_data_batched(in_data dune.eventlogbulkentrydata[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
data_entry record = NULL;
|
|
BEGIN
|
|
FOREACH data_entry IN ARRAY in_data
|
|
LOOP
|
|
PERFORM add_event_log_data(data_entry.game_event_owner, data_entry.universe_time, data_entry.map_name, data_entry.partition_id, data_entry.event_type,
|
|
data_entry.x_location, data_entry.y_location, data_entry.z_location, data_entry.player_facing_event, data_entry.custom_args);
|
|
END LOOP;
|
|
END $function$
|
|
|
|
|
|
-- add_guild_invite(in_player_id bigint, in_guild_id bigint, in_sender_player_id bigint, in_invite_sent_timespan bigint, in_max_guild_invites_per_guild integer) -> void
|
|
-- oid: 58121 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_guild_invite(in_player_id bigint, in_guild_id bigint, in_sender_player_id bigint, in_invite_sent_timespan bigint, in_max_guild_invites_per_guild integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
invite_count INTEGER := 0;
|
|
out_invite_id INTEGER;
|
|
out_guild_name TEXT;
|
|
out_guild_description TEXT;
|
|
out_player_name TEXT;
|
|
out_sender_name TEXT;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- check if guild exists
|
|
SELECT guild_name, guild_description INTO out_guild_name, out_guild_description FROM guilds WHERE guild_id = in_guild_id;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trying to add invite to non existing guild %.', in_guild_id;
|
|
END IF;
|
|
|
|
-- check if we've reached the invite limit
|
|
SELECT INTO invite_count COUNT(*) FROM guild_invites WHERE guild_invites.guild_id = in_guild_id;
|
|
IF invite_count >= in_max_guild_invites_per_guild THEN
|
|
RAISE EXCEPTION 'Cannot insert more than % guild invites per guild.', in_max_guild_invites_per_guild;
|
|
END IF;
|
|
|
|
-- check if this player already has an invite to this guild
|
|
IF EXISTS (SELECT FROM guild_invites WHERE guild_id = in_guild_id AND player_id = in_player_id) THEN
|
|
RAISE EXCEPTION 'Trying to add invite to a player that already has an invite to this guild.';
|
|
END IF;
|
|
|
|
-- add invite
|
|
INSERT INTO guild_invites("guild_id", "player_id", "sender_player_id", "invite_sent_timespan") VALUES(in_guild_id, in_player_id, in_sender_player_id, in_invite_sent_timespan) RETURNING "invite_id" INTO out_invite_id;
|
|
|
|
SELECT player_state.character_name INTO out_player_name
|
|
FROM player_state
|
|
WHERE player_state.player_controller_id = in_player_id;
|
|
|
|
SELECT player_state.character_name INTO out_sender_name
|
|
FROM player_state
|
|
WHERE player_state.player_controller_id = in_sender_player_id;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format(
|
|
'add_invite#{"InviteId" : %s, "PlayerId" : %s , "GuildId" : %s, "GuildName" : "%s", "PlayerName" : "%s", "GuildDescription" : "%s", "SenderPlayerId" : %s, "SenderPlayerName" : "%s", "InviteSentUniverseTime" : %s}',
|
|
out_invite_id, in_player_id, in_guild_id, out_guild_name, out_player_name, out_guild_description, in_sender_player_id, out_sender_name, in_invite_sent_timespan));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- add_guild_member(in_player_id bigint, in_guild_id bigint, in_role_id smallint, in_max_guild_count_per_player integer, in_max_members_per_guild integer, in_neutral_faction_id smallint) -> void
|
|
-- oid: 58122 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_guild_member(in_player_id bigint, in_guild_id bigint, in_role_id smallint, in_max_guild_count_per_player integer, in_max_members_per_guild integer, in_neutral_faction_id smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
guild_count INTEGER := 0;
|
|
should_clear_invites SMALLINT := 0;
|
|
player_faction_id SMALLINT;
|
|
guild_record record;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- we need to check if the player is already part of max amount of guilds before being able to add them
|
|
SELECT INTO guild_count COUNT(*) FROM guild_members WHERE player_id = in_player_id;
|
|
IF guild_count >= in_max_guild_count_per_player THEN
|
|
RAISE EXCEPTION 'Cannot insert more than % guild entries for each user.', in_max_guild_count_per_player;
|
|
END IF;
|
|
|
|
SELECT * INTO guild_record
|
|
FROM guilds
|
|
WHERE guild_id = in_guild_id;
|
|
|
|
-- check if guild exists
|
|
IF guild_record IS NULL THEN
|
|
RAISE EXCEPTION 'Trying to add user to non existing guild %.', in_guild_id;
|
|
END IF;
|
|
|
|
player_faction_id := get_player_faction(in_player_id, in_neutral_faction_id);
|
|
|
|
IF player_faction_id != in_neutral_faction_id AND guild_record.guild_faction != in_neutral_faction_id AND player_faction_id != guild_record.guild_faction THEN
|
|
RAISE EXCEPTION 'Trying to add user to with non compatible. player faction: %, guild faction: %', player_faction_id, guild_record.guild_faction;
|
|
END IF;
|
|
|
|
IF (SELECT COUNT(*) FROM guild_members where guild_members.guild_id = in_guild_id) = in_max_members_per_guild - 1 THEN
|
|
should_clear_invites := 1;
|
|
END IF;
|
|
|
|
-- insert member
|
|
INSERT INTO guild_members("player_id", "guild_id", "role_id") VALUES(in_player_id, in_guild_id, in_role_id);
|
|
|
|
-- delete invite
|
|
IF should_clear_invites = 1 THEN
|
|
DELETE FROM guild_invites WHERE guild_id = in_guild_id;
|
|
ELSE
|
|
DELETE FROM guild_invites WHERE guild_id = in_guild_id AND player_id = in_player_id;
|
|
END IF;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('add_player#{"PlayerId" : %s , "PlayerFactionId" : %s, "GuildId" : %s, "RoleId" : %s, "ShouldClearInvites" : %s}', in_player_id, player_faction_id, in_guild_id, in_role_id, should_clear_invites));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- add_landclaim_segment(in_totem_id bigint, in_grid_location_x bigint, in_grid_location_y bigint) -> void
|
|
-- oid: 58123 kind: FUNCTION category: landclaim
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_landclaim_segment(in_totem_id bigint, in_grid_location_x bigint, in_grid_location_y bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO landclaim_segments(totem_id, grid_location_x, grid_location_y)
|
|
VALUES(in_totem_id, in_grid_location_x, in_grid_location_y);
|
|
END; $function$
|
|
|
|
|
|
-- add_map_areas_surveyed_items(in_account_id bigint, in_area_id smallint, in_survey_point_marker_id bigint, in_surveyed_items_target jsonb, in_surveyed_items_progress jsonb, in_map_name text) -> void
|
|
-- oid: 58124 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_map_areas_surveyed_items(in_account_id bigint, in_area_id smallint, in_survey_point_marker_id bigint, in_surveyed_items_target jsonb, in_surveyed_items_progress jsonb, in_map_name text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO map_areas("account_id", "area_id", "survey_point_marker_id", "items_surveyed_target", "items_surveyed_progress", "map_name")
|
|
VALUES(in_account_id, in_area_id, in_survey_point_marker_id, in_surveyed_items_target, in_surveyed_items_progress, in_map_name)
|
|
ON CONFLICT ("account_id", "area_id", "map_name") DO UPDATE SET "survey_point_marker_id" = in_survey_point_marker_id, "items_surveyed_target" = in_surveyed_items_target, "items_surveyed_progress" = in_surveyed_items_progress
|
|
WHERE map_areas.account_id = in_account_id AND map_areas.area_id = in_area_id and map_areas.map_name = in_map_name;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- add_map_areas_time_discovered(in_account_id bigint, in_area_id smallint, in_time_discovered timestamp without time zone, in_map_name text) -> void
|
|
-- oid: 58125 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_map_areas_time_discovered(in_account_id bigint, in_area_id smallint, in_time_discovered timestamp without time zone, in_map_name text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO map_areas("account_id", "area_id", "time_discovered", "map_name")
|
|
VALUES(in_account_id, in_area_id, in_time_discovered, in_map_name)
|
|
ON CONFLICT ("account_id", "area_id", "map_name") DO UPDATE SET "time_discovered" = in_time_discovered
|
|
WHERE map_areas.account_id = in_account_id AND map_areas.area_id = in_area_id and map_areas.map_name = in_map_name;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- add_map_areas_time_first_entered(in_account_id bigint, in_area_id smallint, in_time_first_entered timestamp without time zone, in_map_name text) -> void
|
|
-- oid: 58126 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_map_areas_time_first_entered(in_account_id bigint, in_area_id smallint, in_time_first_entered timestamp without time zone, in_map_name text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO map_areas("account_id", "area_id", "time_first_entered", "map_name")
|
|
VALUES(in_account_id, in_area_id, in_time_first_entered, in_map_name)
|
|
ON CONFLICT ("account_id", "area_id", "map_name") DO UPDATE SET "time_first_entered" = in_time_first_entered
|
|
WHERE map_areas.account_id = in_account_id AND map_areas.area_id = in_area_id and map_areas.map_name = in_map_name;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- add_partition_unique(in_map text, in_definition jsonb, in_dimension bigint, in_label text) -> bigint
|
|
-- oid: 58127 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_partition_unique(in_map text, in_definition jsonb, in_dimension bigint, in_label text DEFAULT NULL::text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
v_partition_id bigint;
|
|
BEGIN
|
|
-- Don't use a constraint right now, this is only a dev-only helper function.
|
|
-- We could add a constraint, but would need to check the performance of constraint on the jsonb field.
|
|
insert into world_partition (map, partition_definition, dimension_index, label)
|
|
select in_map, in_definition, in_dimension, in_label
|
|
where not exists (
|
|
select 1 from world_partition where map = in_map and partition_definition = in_definition and dimension_index = in_dimension
|
|
) returning partition_id into v_partition_id;
|
|
return v_partition_id;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- add_party_invite(in_sender_player_id bigint, in_sender_platform_name text, in_sender_platform_session_id text, in_player_id bigint, in_max_party_member_count integer, in_invite_sent_timespan bigint) -> void
|
|
-- oid: 58128 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.add_party_invite(in_sender_player_id bigint, in_sender_platform_name text, in_sender_platform_session_id text, in_player_id bigint, in_max_party_member_count integer, in_invite_sent_timespan bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_already_in_party BOOLEAN;
|
|
out_already_invited BOOLEAN;
|
|
out_sender_existing_party_id BIGINT;
|
|
out_sender_party_count INTEGER;
|
|
out_invite_id BIGINT;
|
|
out_player_name TEXT;
|
|
out_sender_name TEXT;
|
|
BEGIN
|
|
|
|
-- check if invited player is already invited
|
|
SELECT INTO out_already_invited EXISTS (SELECT 1 FROM party_invites where player_id = in_player_id AND sender_player_id = in_sender_player_id);
|
|
IF out_already_invited THEN
|
|
RAISE EXCEPTION 'The player % already has an invite from %.', in_player_id, in_sender_player_id;
|
|
END IF;
|
|
|
|
-- check if the sender party is full
|
|
SELECT party_id INTO out_sender_existing_party_id from parties where party_leader_id = in_sender_player_id;
|
|
SELECT INTO out_sender_party_count COUNT(*) FROM party_members WHERE party_id = out_sender_existing_party_id;
|
|
|
|
IF out_sender_existing_party_id IS NOT NULL AND out_sender_party_count >= in_max_party_member_count THEN
|
|
RAISE EXCEPTION 'Trying to invite player % for a party id % that is full.', in_player_id, out_sender_existing_party_id;
|
|
END IF;
|
|
|
|
-- add invite
|
|
INSERT INTO party_invites("player_id", "party_id", "sender_player_id", "sender_platform_name", "sender_platform_session_id", "invite_sent_timespan")
|
|
VALUES(in_player_id, out_sender_existing_party_id, in_sender_player_id, in_sender_platform_name, in_sender_platform_session_id, in_invite_sent_timespan) RETURNING "invite_id" INTO out_invite_id;
|
|
|
|
SELECT player_state.character_name INTO out_player_name
|
|
FROM player_state WHERE player_state.player_controller_id = in_player_id;
|
|
|
|
SELECT player_state.character_name INTO out_sender_name
|
|
FROM player_state WHERE player_state.player_controller_id = in_sender_player_id;
|
|
|
|
PERFORM pg_notify('party_notify_channel', format(
|
|
'add_invite#{"InviteId" : %s, "SenderId" : %s, "SenderName" : "%s", "PlayerId" : %s , "PlayerName" : "%s", "InviteSentUniverseTime" : %s}',
|
|
out_invite_id, in_sender_player_id, out_sender_name, in_player_id, out_player_name, in_invite_sent_timespan));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- adjust_player_virtual_currency_balance(in_controller_id bigint, in_currency_id smallint, in_delta bigint) -> bigint
|
|
-- oid: 58129 kind: FUNCTION category: currency
|
|
|
|
CREATE OR REPLACE FUNCTION dune.adjust_player_virtual_currency_balance(in_controller_id bigint, in_currency_id smallint, in_delta bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
current_balance BIGINT;
|
|
current_delta BIGINT;
|
|
new_delta BIGINT;
|
|
fls_id TEXT;
|
|
function_oid oid;
|
|
BEGIN
|
|
SELECT INTO current_balance balance from player_virtual_currency_balances WHERE player_controller_id = in_controller_id AND currency_id = in_currency_id;
|
|
INSERT INTO player_virtual_currency_balances("player_controller_id", "currency_id", "balance")
|
|
VALUES (in_controller_id, in_currency_id, in_delta)
|
|
ON CONFLICT (player_controller_id, currency_id) DO UPDATE SET balance = (player_virtual_currency_balances.balance + in_delta)
|
|
RETURNING balance INTO current_balance;
|
|
|
|
IF in_currency_id = get_solaris_id() THEN
|
|
GET DIAGNOSTICS function_oid = PG_ROUTINE_OID;
|
|
PERFORM log_event_solaris(function_oid, 'update_solaris', in_controller_id, current_balance, in_delta);
|
|
END IF;
|
|
|
|
current_delta = 0;
|
|
IF current_balance < 0 THEN
|
|
SELECT acc."user"
|
|
INTO fls_id
|
|
FROM accounts acc
|
|
JOIN player_state ps on ps.account_id = acc.id
|
|
WHERE ps.account_id = in_player_id
|
|
LIMIT 1;
|
|
|
|
PERFORM log_cheating(COALESCE(fls_id, in_player_id::text), 'negative_solaris');
|
|
|
|
INSERT INTO player_virtual_currency_balances("player_controller_id", "currency_id", "balance")
|
|
VALUES (in_controller_id, in_currency_id, 0)
|
|
ON CONFLICT (player_controller_id, currency_id) DO UPDATE SET balance = 0;
|
|
current_delta = current_balance;
|
|
END IF;
|
|
|
|
new_delta = in_delta + current_delta;
|
|
RETURN new_delta;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- admin_get_character_details(in_account_id bigint) -> TABLE(account_id bigint, player_id text, character_name text, online_status text, last_avatar_activity timestamp with time zone, class text, map text, transform dune.transform, server_id text, partition_id bigint, partition_label text, dimension_index integer, gas_attributes jsonb, properties jsonb, slot_name text, fgl_data text)
|
|
-- oid: 58130 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.admin_get_character_details(in_account_id bigint)
|
|
RETURNS TABLE(account_id bigint, player_id text, character_name text, online_status text, last_avatar_activity timestamp with time zone, class text, map text, transform dune.transform, server_id text, partition_id bigint, partition_label text, dimension_index integer, gas_attributes jsonb, properties jsonb, slot_name text, fgl_data text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query SELECT player_state.account_id, accounts.user As player_id, player_state.character_name, CASE WHEN is_player_offline(accounts.user) THEN 'Offline' ELSE 'Online' END AS online_status, player_state.last_avatar_activity,
|
|
actors.class, actors.map, actors.transform, player_state.server_id, actors.partition_id, world_partition.label, actors.dimension_index,
|
|
actors.gas_attributes, actors.properties, actor_fgl_entities.slot_name,
|
|
string_agg(cast(to_json((select d from (select fgl_entities.components) d)) as varchar), ', ') as fgl_data
|
|
from fgl_entities
|
|
left join actor_fgl_entities on fgl_entities.entity_id = actor_fgl_entities.entity_id
|
|
left join actors on actor_fgl_entities.actor_id = actors.id
|
|
left join player_state on player_state.player_pawn_id = actors.id
|
|
left join accounts on accounts.id = player_state.account_id
|
|
left join world_partition on world_partition.partition_id = actors.partition_id
|
|
where player_state.account_id = in_account_id
|
|
and actor_fgl_entities.slot_name = 'DuneCharacter'
|
|
group by player_state.account_id, player_state.character_name, player_state.last_avatar_activity, accounts.user,
|
|
actors.class, actors.map, actors.transform, player_state.server_id, actors.partition_id, world_partition.label, actors.dimension_index,
|
|
actors.gas_attributes, actors.properties, actor_fgl_entities.slot_name;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- admin_get_character_ids(in_search_term text) -> TABLE(id bigint, "user" text, character_name text)
|
|
-- oid: 58131 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.admin_get_character_ids(in_search_term text)
|
|
RETURNS TABLE(id bigint, "user" text, character_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
select accounts.id, accounts.user, player_state.character_name
|
|
from accounts
|
|
left join player_state on player_state.account_id = accounts.id
|
|
where lower(accounts.user) like in_search_term or lower(player_state.character_name) like in_search_term;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- admin_get_inventory_details(in_account_id bigint) -> TABLE(inventory_id bigint, item_id bigint, stack_size integer, template_id text, acquisition_time bigint)
|
|
-- oid: 58132 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.admin_get_inventory_details(in_account_id bigint)
|
|
RETURNS TABLE(inventory_id bigint, item_id bigint, stack_size integer, template_id text, acquisition_time bigint)
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select
|
|
inventories.id as inventory_id, items.id as item_id, items.stack_size, items.template_id, items.acquisition_time
|
|
from
|
|
items
|
|
left join
|
|
inventories on inventories.id = items.inventory_id
|
|
left join
|
|
player_state on inventories.actor_id = player_state.player_pawn_id
|
|
where
|
|
player_state.account_id = in_account_id
|
|
order by
|
|
template_id;
|
|
$function$
|
|
|
|
|
|
-- admin_get_journey_details(in_player_id text, in_story_node_id text) -> TABLE(out_story_node_id text, out_override_reward_block boolean, out_has_pending_reward boolean, out_complete_condition_state jsonb, out_reveal_condition_state jsonb, out_fail_condition_state jsonb, out_metadata_state jsonb, out_reset_group dune.journeystoryresetgroup)
|
|
-- oid: 58133 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.admin_get_journey_details(in_player_id text, in_story_node_id text DEFAULT '%%'::text)
|
|
RETURNS TABLE(out_story_node_id text, out_override_reward_block boolean, out_has_pending_reward boolean, out_complete_condition_state jsonb, out_reveal_condition_state jsonb, out_fail_condition_state jsonb, out_metadata_state jsonb, out_reset_group dune.journeystoryresetgroup)
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select story_node_id, override_reward_block, has_pending_reward, complete_condition_state, reveal_condition_state, fail_condition_state, metadata_state, reset_group
|
|
from journey_story_node
|
|
where story_node_id like in_story_node_id
|
|
and account_id in (
|
|
select id
|
|
from accounts a
|
|
where a.user = in_player_id
|
|
);
|
|
$function$
|
|
|
|
|
|
-- admin_get_mnemonic_recall_details(in_account_id bigint) -> TABLE(mnemonic_recall_id bigint, lesson_id text, lesson_state bigint, lesson_progress integer)
|
|
-- oid: 58134 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.admin_get_mnemonic_recall_details(in_account_id bigint)
|
|
RETURNS TABLE(mnemonic_recall_id bigint, lesson_id text, lesson_state bigint, lesson_progress integer)
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select
|
|
mnemonic_recall.id, lesson_id, lesson_state, lesson_progress
|
|
from
|
|
mnemonic_recall
|
|
where
|
|
mnemonic_recall.account_id = in_account_id
|
|
$function$
|
|
|
|
|
|
-- admin_get_partitions() -> TABLE(out_partition_id bigint, out_server_id text, out_partition_definition jsonb, out_dimension_index integer, out_blocked boolean, out_label text, out_map text)
|
|
-- oid: 58135 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.admin_get_partitions()
|
|
RETURNS TABLE(out_partition_id bigint, out_server_id text, out_partition_definition jsonb, out_dimension_index integer, out_blocked boolean, out_label text, out_map text)
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select * from load_partition_definition_map();
|
|
$function$
|
|
|
|
|
|
-- admin_move_offline_player(in_fls_id text, in_target_partition_name text, in_target_location dune.vector) -> void
|
|
-- oid: 58136 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.admin_move_offline_player(in_fls_id text, in_target_partition_name text, in_target_location dune.vector)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
if not (select is_player_offline(in_fls_id)) then
|
|
raise exception 'Player must be Offline';
|
|
end if;
|
|
|
|
if not exists(select 1 from world_partition where label = in_target_partition_name) then
|
|
raise exception 'Partition with name % not found', in_target_partition_name;
|
|
end if;
|
|
|
|
perform (with target_partition as (
|
|
select partition_id, map, dimension_index
|
|
from world_partition
|
|
where label = in_target_partition_name
|
|
limit 1
|
|
)
|
|
select admin_move_offline_player_to_partition(in_fls_id, target_partition.partition_id, in_target_location)
|
|
from target_partition);
|
|
end
|
|
$function$
|
|
|
|
|
|
-- admin_move_offline_player_to_partition(in_fls_id text, in_target_partition_id bigint, in_target_location dune.vector) -> void
|
|
-- oid: 58137 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.admin_move_offline_player_to_partition(in_fls_id text, in_target_partition_id bigint, in_target_location dune.vector)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
if not (select is_player_offline(in_fls_id)) then
|
|
-- CAVEAT: DirectorDbApi.TryMoveOfflinePlayerToPartition depends on this string.
|
|
raise exception 'Player must be Offline';
|
|
end if;
|
|
|
|
if not exists(select 1 from world_partition where partition_id = in_target_partition_id) then
|
|
raise exception 'Partition with ID % not found', in_target_partition_id;
|
|
end if;
|
|
|
|
raise notice 'Moving player % to partition % location x=%, y=%, z=%', in_fls_id, in_target_partition_id, in_target_location.x, in_target_location.y, in_target_location.z;
|
|
|
|
with target_partition as (
|
|
select partition_id, map, dimension_index
|
|
from world_partition
|
|
where partition_id = in_target_partition_id
|
|
limit 1
|
|
), target_pawn_id as (
|
|
select player_state.player_pawn_id as id
|
|
from accounts, player_state
|
|
where accounts.user = in_fls_id and accounts.id = player_state.account_id
|
|
limit 1
|
|
), update_overmap_player_location as (
|
|
select
|
|
case
|
|
when target_partition.map = 'Overmap' then overmap_save_player_survival_data(target_pawn_id.id, null, false, in_target_location)
|
|
else null
|
|
end
|
|
from target_pawn_id, target_partition
|
|
)
|
|
update actors
|
|
set
|
|
transform = (in_target_location, (transform).rotation),
|
|
map = upgrade_map_name(target_partition.map),
|
|
dimension_index = target_partition.dimension_index,
|
|
partition_id = target_partition.partition_id
|
|
from
|
|
target_pawn_id, target_partition, update_overmap_player_location
|
|
where actors.id = target_pawn_id.id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- admin_read_player_tags(in_account_id bigint) -> TABLE(tags text)
|
|
-- oid: 58138 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.admin_read_player_tags(in_account_id bigint)
|
|
RETURNS TABLE(tags text)
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select
|
|
pt.tag
|
|
from
|
|
player_tags as pt
|
|
where
|
|
pt.account_id = in_account_id
|
|
$function$
|
|
|
|
|
|
-- advance_items_id_sequencer(count bigint) -> bigint
|
|
-- oid: 58139 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.advance_items_id_sequencer(count bigint DEFAULT 1)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
next_val BIGINT;
|
|
next_free BIGINT;
|
|
BEGIN
|
|
IF count < 1 THEN
|
|
RAISE EXCEPTION 'count must be >= 1';
|
|
END IF;
|
|
|
|
PERFORM pg_advisory_xact_lock(('items_id_seq'::regclass)::oid::bigint);
|
|
|
|
next_val := nextval('items_id_seq'::regclass);
|
|
|
|
-- next free id after reserving `count` ids starting at next_val
|
|
next_free := next_val + count;
|
|
|
|
-- make the next nextval() return next_free
|
|
PERFORM setval('items_id_seq'::regclass, next_free, false);
|
|
|
|
RETURN next_val;
|
|
END $function$
|
|
|
|
|
|
-- assign_actor_id(in_class text) -> bigint
|
|
-- oid: 58140 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.assign_actor_id(in_class text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
new_id BIGINT;
|
|
BEGIN
|
|
INSERT INTO actors(id) VALUES(DEFAULT) RETURNING id INTO new_id;
|
|
PERFORM add_actor_audit(new_id, in_class);
|
|
|
|
RETURN new_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- base_backup_delete(in_base_backup_id bigint) -> void
|
|
-- oid: 58141 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_delete(in_base_backup_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
actors_to_destroy BIGINT[];
|
|
BEGIN
|
|
DELETE FROM actors a WHERE id = ANY(
|
|
SELECT actor_id
|
|
FROM base_backup_linked_actors bbla
|
|
WHERE bbla.id = in_base_backup_id
|
|
);
|
|
|
|
DELETE FROM base_backups WHERE id = in_base_backup_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- base_backup_find_totems_from_player_owner(in_player_id bigint) -> TABLE(totem_id bigint)
|
|
-- oid: 58142 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_find_totems_from_player_owner(in_player_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 par.permission_actor_id = t.id
|
|
WHERE par.player_id = in_player_id AND par.rank = 1;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- base_backup_finish_placing(in_base_backup_id bigint) -> void
|
|
-- oid: 58143 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_finish_placing(in_base_backup_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
WITH base_info AS (
|
|
SELECT
|
|
bb.id AS base_backup_id,
|
|
a.partition_id,
|
|
a.dimension_index,
|
|
a.map
|
|
FROM
|
|
base_backups bb
|
|
JOIN actors a on bb.player_id = a.id
|
|
WHERE
|
|
bb.id = in_base_backup_id
|
|
)
|
|
UPDATE actors
|
|
SET
|
|
partition_id = base_info.partition_id,
|
|
dimension_index = base_info.dimension_index,
|
|
map = base_info.map
|
|
FROM
|
|
base_backup_linked_actors bbl
|
|
JOIN base_info ON bbl.id = base_info.base_backup_id
|
|
WHERE
|
|
actors.id = bbl.actor_id;
|
|
|
|
DELETE FROM actor_state a
|
|
WHERE actor_id = ANY(
|
|
SELECT actor_id
|
|
FROM base_backup_linked_actors bbla
|
|
WHERE bbla.id = in_base_backup_id
|
|
);
|
|
|
|
DELETE FROM base_backups
|
|
WHERE id = in_base_backup_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- base_backup_get_actors_to_spawn(in_base_backup_id bigint) -> SETOF dune.actorspawninfo
|
|
-- oid: 58144 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_get_actors_to_spawn(in_base_backup_id bigint)
|
|
RETURNS SETOF dune.actorspawninfo
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT a.id, a.class as class_name, a.transform, a.partition_id, a.dimension_index
|
|
FROM actors as a
|
|
WHERE a.id IN (
|
|
SELECT actor_id FROM base_backup_linked_actors as bbla WHERE bbla.id = in_base_backup_id
|
|
);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- base_backup_get_available_backups(in_player_id bigint) -> TABLE(id bigint, base_backup_name text, totem_id bigint, totem_buildable_type text, landclaim_original_global_location real[], base_backup_map text)
|
|
-- oid: 58145 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_get_available_backups(in_player_id bigint)
|
|
RETURNS TABLE(id bigint, base_backup_name text, totem_id bigint, totem_buildable_type text, landclaim_original_global_location real[], base_backup_map text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
RETURN QUERY
|
|
SELECT
|
|
bb.id,
|
|
bb.base_backup_name,
|
|
t.id AS totem_id,
|
|
p.building_type,
|
|
t.landclaim_original_global_location,
|
|
a.map
|
|
FROM base_backups bb
|
|
JOIN base_backup_linked_actors bbla ON bbla.id = bb.id
|
|
JOIN totems t ON bbla.actor_id = t.id
|
|
JOIN actors a ON a.id = t.id
|
|
JOIN placeables p ON p.id = a.id
|
|
WHERE bb.player_id = in_player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- base_backup_get_buildable_data(in_base_backup_id bigint) -> TABLE(buildable_type text, total_count integer)
|
|
-- oid: 58146 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_get_buildable_data(in_base_backup_id bigint)
|
|
RETURNS TABLE(buildable_type text, total_count integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT t.buildable_type, SUM(t.cnt)::INT AS total_count
|
|
FROM (
|
|
SELECT bi.building_type AS buildable_type, COUNT(*) AS cnt
|
|
FROM base_backup_linked_actors bla
|
|
JOIN building_instances bi ON bla.actor_id = bi.building_id
|
|
WHERE
|
|
bla.id = in_base_backup_id AND
|
|
(bi.building_flags IS NULL OR (bi.building_flags & (1 << 2) = 0 AND bi.building_flags & (1 << 7) = 0)) -- flag 2 and 7 not enabled, which relates to holograms and extensions
|
|
GROUP BY bi.building_type
|
|
|
|
UNION ALL
|
|
|
|
SELECT p.building_type AS buildable_type, COUNT(*) AS cnt
|
|
FROM base_backup_linked_actors bla
|
|
JOIN placeables p ON bla.actor_id = p.id
|
|
WHERE bla.id = in_base_backup_id AND p.is_hologram = FALSE
|
|
GROUP BY p.building_type
|
|
) t
|
|
GROUP BY t.buildable_type;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- base_backup_get_data(in_base_backup_id bigint) -> dune.getbasebackupdata
|
|
-- oid: 58147 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_get_data(in_base_backup_id bigint)
|
|
RETURNS dune.getbasebackupdata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
base_backup_name TEXT;
|
|
totem_data BaseBackupTotemData;
|
|
buildings_array BaseBackupBuildingItem[];
|
|
placeables_array BaseBackupPlaceableItem[];
|
|
BEGIN
|
|
|
|
SELECT bb.base_backup_name
|
|
INTO base_backup_name
|
|
FROM base_backups bb
|
|
WHERE bb.id = in_base_backup_id;
|
|
|
|
totem_data := base_backup_get_totem_data(in_base_backup_id);
|
|
|
|
-- building pieces
|
|
SELECT array_agg((bi.building_id, bi.instance_id, bi.building_type, bi.transform, bi.building_flags)::BaseBackupBuildingItem)
|
|
into buildings_array
|
|
FROM
|
|
building_instances bi
|
|
JOIN base_backup_linked_actors bbla ON bi.building_id = bbla.actor_id
|
|
WHERE bbla.id = in_base_backup_id;
|
|
|
|
-- placeables
|
|
SELECT array_agg((p.building_type, a.transform)::BaseBackupPlaceableItem)
|
|
into placeables_array
|
|
FROM
|
|
placeables p
|
|
JOIN actors a ON p.id = a.id
|
|
JOIN base_backup_linked_actors bbla ON a.id = bbla.actor_id
|
|
WHERE
|
|
bbla.id = in_base_backup_id;
|
|
|
|
return ROW(base_backup_name, totem_data, buildings_array, placeables_array)::GetBaseBackupData;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- base_backup_get_totem_data(in_base_backup_id bigint) -> dune.basebackuptotemdata
|
|
-- oid: 58148 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_get_totem_data(in_base_backup_id bigint)
|
|
RETURNS dune.basebackuptotemdata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
totem_id BIGINT;
|
|
result BaseBackupTotemData;
|
|
BEGIN
|
|
SELECT t.id
|
|
INTO totem_id
|
|
FROM totems t JOIN base_backup_linked_actors bbla ON t.id = bbla.actor_id
|
|
WHERE bbla.id = in_base_backup_id
|
|
LIMIT 1;
|
|
|
|
IF totem_id IS NULL THEN
|
|
RAISE EXCEPTION 'No totem found for base_backup id %', in_base_backup_id;
|
|
END IF;
|
|
|
|
result := base_backup_get_totem_data_from_totem_id(totem_id);
|
|
|
|
RETURN result;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- base_backup_get_totem_data_from_totem_id(in_totem_id bigint) -> dune.basebackuptotemdata
|
|
-- oid: 58149 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_get_totem_data_from_totem_id(in_totem_id bigint)
|
|
RETURNS dune.basebackuptotemdata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result BaseBackupTotemData;
|
|
BEGIN
|
|
SELECT
|
|
t.id,
|
|
p.building_type,
|
|
a.map,
|
|
t.landclaim_original_global_location,
|
|
t.landclaim_original_global_yaw_rotation,
|
|
t.landclaim_vertical_level
|
|
INTO
|
|
result.totem_actor_id,
|
|
result.totem_building_type,
|
|
result.totem_map,
|
|
result.landclaim_original_global_location,
|
|
result.landclaim_original_global_yaw_rotation,
|
|
result.landclaim_vertical_level
|
|
FROM totems t
|
|
JOIN placeables p ON p.id = t.id
|
|
JOIN actors a ON a.id = t.id
|
|
WHERE t.id = in_totem_id
|
|
LIMIT 1;
|
|
|
|
IF result.totem_actor_id IS NULL THEN
|
|
RAISE EXCEPTION 'No totem found for totem_id %', in_totem_id;
|
|
END IF;
|
|
|
|
SELECT array_agg(ROW(grid_location_x, grid_location_y)::SMALLINTPOINT)
|
|
INTO result.landclaim_grid
|
|
FROM landclaim_segments s
|
|
WHERE s.totem_id = result.totem_actor_id;
|
|
|
|
RETURN result;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- base_backup_get_totem_id(backup_id bigint) -> bigint
|
|
-- oid: 58150 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_get_totem_id(backup_id bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result BIGINT;
|
|
BEGIN
|
|
SELECT t.id
|
|
INTO result
|
|
FROM totems t
|
|
JOIN base_backup_linked_actors bbla ON t.id = bbla.actor_id
|
|
WHERE bbla.id = backup_id
|
|
LIMIT 1;
|
|
|
|
IF result IS NULL THEN
|
|
RAISE EXCEPTION 'No totem found for base_backup id %', backup_id;
|
|
END IF;
|
|
|
|
RETURN result;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- base_backup_recycle(in_base_backup_id bigint, in_target_inventory_id bigint) -> integer
|
|
-- oid: 58151 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_recycle(in_base_backup_id bigint, in_target_inventory_id bigint)
|
|
RETURNS integer
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
base_backup_items_moved INT;
|
|
BEGIN
|
|
UPDATE items
|
|
SET inventory_id = in_target_inventory_id
|
|
FROM
|
|
inventories inv
|
|
JOIN base_backup_linked_actors bbla ON inv.actor_id = bbla.actor_id
|
|
WHERE
|
|
items.inventory_id = inv.id
|
|
AND bbla.id = in_base_backup_id;
|
|
|
|
get diagnostics base_backup_items_moved = ROW_COUNT;
|
|
|
|
-- Re-organize the index of all the items
|
|
UPDATE items
|
|
SET position_index = new_index
|
|
FROM (
|
|
SELECT
|
|
id,
|
|
ROW_NUMBER() OVER (ORDER BY position_index) - 1 AS new_index
|
|
FROM items
|
|
WHERE inventory_id = in_target_inventory_id
|
|
) AS sub
|
|
WHERE items.id = sub.id;
|
|
|
|
PERFORM base_backup_delete(in_base_backup_id);
|
|
|
|
return base_backup_items_moved;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- base_backup_save(in_player_actor_id bigint, in_base_backup_name text, in_building_pieces_to_link dune.basebackupbuildingitem[], in_placeables_to_link bigint[], in_placeables_to_remove_totem_owner bigint[]) -> bigint
|
|
-- oid: 58152 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_save(in_player_actor_id bigint, in_base_backup_name text, in_building_pieces_to_link dune.basebackupbuildingitem[], in_placeables_to_link bigint[], in_placeables_to_remove_totem_owner bigint[])
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
v_backup_id BIGINT;
|
|
totem_id BIGINT;
|
|
BEGIN
|
|
-- Find and Validate the Totem exists in the list
|
|
SELECT t.id INTO totem_id
|
|
FROM totems t
|
|
JOIN unnest(in_placeables_to_link) AS ai(actor_id) ON t.id = ai.actor_id
|
|
LIMIT 1;
|
|
|
|
IF totem_id IS NULL THEN
|
|
RAISE EXCEPTION 'No totem found for base_backup_save';
|
|
END IF;
|
|
|
|
INSERT INTO base_backups(player_id, base_backup_name)
|
|
VALUES (in_player_actor_id, in_base_backup_name) RETURNING id INTO v_backup_id;
|
|
|
|
-- for each building_id, create a new actor for those building pieces and then assign that new building_id to the building pieces.
|
|
with
|
|
input as (select DISTINCT building_id from unnest(in_building_pieces_to_link)),
|
|
instances_input as (select building_id, instance_id from unnest(in_building_pieces_to_link)),
|
|
new_actor_ids as (select nextval('actors_id_seq') as new_id, building_id as old_id from input),
|
|
_copy_building_actors as (
|
|
insert into actors("id", "class", "map", "transform", "partition_id", "dimension_index")
|
|
select i.new_id, a."class", a."map", a."transform", a."partition_id", a."dimension_index"
|
|
from new_actor_ids i join actors a on (i.old_id = a.id)),
|
|
_insert_actor_states as (insert into actor_state(actor_id, state) select new_id, 'BaseBackup' from new_actor_ids),
|
|
_insert_buildings as (insert into buildings("id") select new_id from new_actor_ids),
|
|
_insert_base_backup_linked_actors as (insert into base_backup_linked_actors("id", "actor_id") select v_backup_id, new_id from new_actor_ids)
|
|
update building_instances bi set building_id = ids.new_id from new_actor_ids ids join instances_input i on (ids.old_id = i.building_id) where bi.building_id = ids.old_id and bi.instance_id = i.instance_id;
|
|
|
|
-- Link all placeables to the linked_base_backup_id and set them to BaseBackup ActorState in actor_state
|
|
INSERT INTO base_backup_linked_actors(id, actor_id)
|
|
SELECT v_backup_id, unnest(in_placeables_to_link);
|
|
|
|
INSERT INTO actor_state(actor_id, state)
|
|
SELECT unnest(in_placeables_to_link), 'BaseBackup'::ActorState;
|
|
|
|
UPDATE placeables
|
|
SET owner_entity_id = NULL
|
|
WHERE id = ANY(in_placeables_to_remove_totem_owner);
|
|
|
|
-- We need to remove permissions for the Totem
|
|
PERFORM permission_actor_destroy(totem_id);
|
|
|
|
-- Remove all invoices from the totem
|
|
PERFORM taxation_remove_invoices_from_totem(totem_id);
|
|
|
|
RETURN v_backup_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- base_backup_save_all_totems_from_player_owner(in_player_id bigint) -> TABLE(base_backup_id bigint)
|
|
-- oid: 58153 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_save_all_totems_from_player_owner(in_player_id bigint)
|
|
RETURNS TABLE(base_backup_id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT base_backup_save_from_totem(in_player_id, totem_id)
|
|
FROM base_backup_find_totems_from_player_owner(in_player_id);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- base_backup_save_from_totem(in_player_id bigint, totem_id bigint) -> bigint
|
|
-- oid: 58154 kind: FUNCTION category: base_backup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.base_backup_save_from_totem(in_player_id bigint, totem_id bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
totem_entity_id BIGINT;
|
|
totem_name TEXT;
|
|
building_pieces_to_link BaseBackupBuildingItem[];
|
|
placeables_to_link BIGINT[];
|
|
placeables_to_remove_totem_owner BIGINT[];
|
|
BEGIN
|
|
SELECT entity_id INTO totem_entity_id
|
|
FROM actor_fgl_entities
|
|
WHERE actor_id = totem_id;
|
|
|
|
SELECT COALESCE(actor_name, '') INTO totem_name
|
|
FROM permission_actor
|
|
WHERE actor_id = totem_id
|
|
LIMIT 1;
|
|
|
|
SELECT array_agg((bi.building_id, bi.instance_id, bi.building_type, bi.transform, bi.building_flags)::BaseBackupBuildingItem)
|
|
INTO building_pieces_to_link
|
|
FROM building_instances bi
|
|
WHERE bi.owner_entity_id = totem_entity_id;
|
|
|
|
SELECT array_agg(p.id)
|
|
INTO placeables_to_link
|
|
FROM placeables p
|
|
WHERE (p.owner_entity_id = totem_entity_id AND p.has_buildable_support = TRUE) OR p.id = totem_id;
|
|
|
|
SELECT array_agg(p.id)
|
|
INTO placeables_to_remove_totem_owner
|
|
FROM placeables p
|
|
WHERE p.owner_entity_id = totem_entity_id AND p.has_buildable_support = FALSE AND p.id != totem_id;
|
|
|
|
RETURN base_backup_save(
|
|
in_player_id,
|
|
totem_name,
|
|
building_pieces_to_link,
|
|
placeables_to_link,
|
|
placeables_to_remove_totem_owner
|
|
);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- break_guild_allegiance(in_guild_id bigint, in_neutral_faction_id smallint) -> void
|
|
-- oid: 58155 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.break_guild_allegiance(in_guild_id bigint, in_neutral_faction_id smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
guild_data_record record;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
SELECT * INTO guild_data_record FROM guilds WHERE guild_id = in_guild_id;
|
|
IF guild_data_record IS NULL THEN
|
|
RAISE EXCEPTION 'Trying to break guild allegiance of a non existing guild: %', in_guild_id;
|
|
END IF;
|
|
|
|
if guild_data_record.guild_faction = in_neutral_faction_id THEN
|
|
RAISE EXCEPTION 'Guild already has neutral faction';
|
|
END IF;
|
|
|
|
UPDATE guilds SET guild_faction = in_neutral_faction_id WHERE guilds.guild_id = in_guild_id;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('break_guild_allegiance#{"GuildId" : %s , "OldGuildFactionDbId" : %s, "NewGuildFactionDbId" : %s}', in_guild_id, guild_data_record.guild_faction, in_neutral_faction_id));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- change_player_faction(in_player_id bigint, in_faction_id smallint, neutral_faction_id smallint, in_utc_time_faction_change timestamp without time zone) -> void
|
|
-- oid: 58157 kind: FUNCTION category: faction
|
|
|
|
CREATE OR REPLACE FUNCTION dune.change_player_faction(in_player_id bigint, in_faction_id smallint, neutral_faction_id smallint, in_utc_time_faction_change timestamp without time zone)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_role_id SMALLINT;
|
|
BEGIN
|
|
|
|
if in_faction_id = neutral_faction_id THEN
|
|
DELETE FROM player_faction WHERE actor_id = in_player_id;
|
|
|
|
PERFORM pg_notify('faction_notify_channel', format('remove_player#{"PlayerId" : %s}', in_player_id));
|
|
ELSE
|
|
INSERT INTO player_faction(actor_id, faction_id, utc_time_faction_change) VALUES(in_player_id, in_faction_id, in_utc_time_faction_change)
|
|
ON CONFLICT (actor_id) DO UPDATE SET faction_id = in_faction_id, utc_time_faction_change = in_utc_time_faction_change;
|
|
|
|
PERFORM pg_notify('faction_notify_channel', format('add_player#{"PlayerId" : %s, "FactionId" : %s}', in_player_id, in_faction_id));
|
|
END IF;
|
|
|
|
PERFORM handle_player_faction_guild_effects(in_player_id, in_faction_id, neutral_faction_id);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- clean_expired_party_invites(in_invite_expire_seconds integer) -> void
|
|
-- oid: 58165 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.clean_expired_party_invites(in_invite_expire_seconds integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM parties_get_exclusive_operation_lock();
|
|
|
|
PERFORM remove_party_invite(invite_id, 0::smallint) FROM party_invites
|
|
WHERE CURRENT_TIMESTAMP > TO_TIMESTAMP(invite_sent_timespan) + INTERVAL '1 second' * in_invite_expire_seconds;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- clean_guild_invites_with_incompatible_faction(in_player_id bigint, in_faction_id smallint, neutral_faction_id smallint) -> void
|
|
-- oid: 58166 kind: FUNCTION category: faction
|
|
|
|
CREATE OR REPLACE FUNCTION dune.clean_guild_invites_with_incompatible_faction(in_player_id bigint, in_faction_id smallint, neutral_faction_id smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
row_record record; -- Variable to hold individual rows
|
|
out_guild_faction_id SMALLINT;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
FOR row_record IN
|
|
SELECT invite_id, guild_invites.guild_id, guilds.guild_faction FROM get_player_guild_invites(in_player_id) as guild_invites
|
|
JOIN guilds ON guilds.guild_id = guild_invites.guild_id
|
|
LOOP
|
|
IF row_record.guild_faction != neutral_faction_id AND in_faction_id != neutral_faction_id AND row_record.guild_faction != in_faction_id THEN
|
|
PERFORM reject_guild_invite(row_record.invite_id);
|
|
END IF;
|
|
END LOOP;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- clean_old_guild_invites(in_cutoff_timespan bigint) -> void
|
|
-- oid: 58167 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.clean_old_guild_invites(in_cutoff_timespan bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM guild_invites WHERE invite_sent_timespan < in_cutoff_timespan;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- clean_stock_for_player(in_player_id bigint) -> void
|
|
-- oid: 58168 kind: FUNCTION category: stock_vendor
|
|
|
|
CREATE OR REPLACE FUNCTION dune.clean_stock_for_player(in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM vendor_stock_cycle WHERE player_id = in_player_id;
|
|
DELETE FROM vendor_stock_state WHERE player_id = in_player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- clean_stock_for_vendors(in_vendor_ids text[]) -> void
|
|
-- oid: 58169 kind: FUNCTION category: stock_vendor
|
|
|
|
CREATE OR REPLACE FUNCTION dune.clean_stock_for_vendors(in_vendor_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM vendor_stock_cycle WHERE vendor_id = ANY(in_vendor_ids);
|
|
DELETE FROM vendor_stock_state WHERE vendor_id = ANY(in_vendor_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- clean_vendors_older_than_timestamp(in_reference_timestamp bigint) -> void
|
|
-- oid: 58170 kind: FUNCTION category: stock_vendor
|
|
|
|
CREATE OR REPLACE FUNCTION dune.clean_vendors_older_than_timestamp(in_reference_timestamp bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
vendors_to_delete TEXT[];
|
|
BEGIN
|
|
SELECT array_agg(vendor_id) INTO vendors_to_delete FROM vendor_stock_cycle WHERE last_interacted_timestamp <= in_reference_timestamp;
|
|
DELETE FROM vendor_stock_cycle WHERE vendor_id = ANY(vendors_to_delete);
|
|
DELETE FROM vendor_stock_state WHERE vendor_id = ANY(vendors_to_delete);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- cleanup_orphaned_entities() -> trigger
|
|
-- oid: 58173 kind: FUNCTION category: cleanup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.cleanup_orphaned_entities()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM fgl_entities WHERE fgl_entities.entity_id = OLD.entity_id;
|
|
RETURN NULL;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- clear_map_areas_data_for_player(in_id bigint) -> void
|
|
-- oid: 58174 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.clear_map_areas_data_for_player(in_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM map_areas WHERE account_id = in_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- complete_journey_nodes_where_prerequisite_nodes_are_complete(story_ids_to_complete text[], prerequisite_completed_story_ids text[]) -> void
|
|
-- oid: 58175 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.complete_journey_nodes_where_prerequisite_nodes_are_complete(story_ids_to_complete text[], prerequisite_completed_story_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF ARRAY_LENGTH(story_ids_to_complete, 1) = 0 OR ARRAY_LENGTH(prerequisite_completed_story_ids, 1) = 0 THEN
|
|
RAISE EXCEPTION 'The story ids to complete array and/or the prerequisite completed story ids array is empty - neither array may be empty';
|
|
END IF;
|
|
|
|
WITH account_ids_to_modify AS (
|
|
SELECT account_id
|
|
FROM journey_story_node
|
|
WHERE story_node_id = ANY(prerequisite_completed_story_ids)
|
|
AND complete_condition_state = to_jsonb(true)
|
|
GROUP BY account_id
|
|
HAVING COUNT(DISTINCT story_node_id) = ARRAY_LENGTH(prerequisite_completed_story_ids, 1)
|
|
)
|
|
INSERT INTO journey_story_node(account_id, story_node_id, override_reward_block, has_pending_reward, complete_condition_state, reveal_condition_state, metadata_state, reset_group, fail_condition_state)
|
|
SELECT ids.account_id, completed_node.story_node_id, false, false, to_jsonb(true), to_jsonb(true), '{}', 'Default', '{}'
|
|
FROM account_ids_to_modify AS ids
|
|
CROSS JOIN (
|
|
SELECT story_node_id
|
|
FROM UNNEST(story_ids_to_complete) AS story_node_id
|
|
) completed_node(story_node_id)
|
|
ON CONFLICT ON CONSTRAINT journey_story_node_pkey
|
|
DO UPDATE SET
|
|
override_reward_block = EXCLUDED.override_reward_block,
|
|
has_pending_reward = EXCLUDED.has_pending_reward,
|
|
complete_condition_state = EXCLUDED.complete_condition_state,
|
|
reveal_condition_state = EXCLUDED.reveal_condition_state;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- complete_journey_story_nodes_for_player(in_player_id text, in_story_node_ids text[]) -> void
|
|
-- oid: 58176 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.complete_journey_story_nodes_for_player(in_player_id text, in_story_node_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF NOT is_player_offline(in_player_id) THEN
|
|
RAISE EXCEPTION 'Cannot execute query because the player is online - they must be offline in order for the journey data to be updated correctly without risking it being overwritten by player actions.';
|
|
END IF;
|
|
|
|
WITH player_account_id AS (
|
|
SELECT id
|
|
FROM accounts a
|
|
WHERE a.user = in_player_id
|
|
)
|
|
INSERT INTO journey_story_node(account_id, story_node_id, override_reward_block, has_pending_reward, complete_condition_state, reveal_condition_state, fail_condition_state, metadata_state, reset_group)
|
|
SELECT player_account_id.id, completed_node.story_node_id, completed_node.override_reward_block, completed_node.has_pending_reward, completed_node.complete_condition_state, completed_node.reveal_condition_state, completed_node.fail_condition_state, completed_node.metadata_state, completed_node.reset_group
|
|
FROM player_account_id
|
|
CROSS JOIN (
|
|
SELECT story_node_id, false, false, to_jsonb(true), to_jsonb(true), jsonb_object(ARRAY[]::text[]), jsonb_object(ARRAY[]::text[]), 'Default'::JourneyStoryResetGroup
|
|
FROM UNNEST(in_story_node_ids) AS story_node_id
|
|
) completed_node(story_node_id, override_reward_block, has_pending_reward, complete_condition_state, reveal_condition_state, fail_condition_state, metadata_state, reset_group)
|
|
ON CONFLICT ON CONSTRAINT journey_story_node_pkey
|
|
DO UPDATE SET
|
|
complete_condition_state = EXCLUDED.complete_condition_state,
|
|
reveal_condition_state = EXCLUDED.reveal_condition_state,
|
|
fail_condition_state = EXCLUDED.fail_condition_state,
|
|
metadata_state = EXCLUDED.metadata_state;
|
|
END $function$
|
|
|
|
|
|
-- corilis_cleanup_map(in_server_info dune.serverinfo, in_map_info dune.coriolismapinfo) -> void
|
|
-- oid: 58177 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.corilis_cleanup_map(in_server_info dune.serverinfo, in_map_info dune.coriolismapinfo)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM delete_markers_for_all_players(in_map_info.marker_types_to_keep, in_server_info.map);
|
|
|
|
IF in_map_info.should_clear_surveyed_areas
|
|
THEN
|
|
DELETE FROM map_areas WHERE map_name = in_server_info.map;
|
|
END IF;
|
|
|
|
IF in_map_info.is_outside_shieldwall
|
|
THEN
|
|
DELETE FROM resourcefield_state WHERE map = in_server_info.map;
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- coriolis_cleanup_farm(in_server_info dune.serverinfo, in_map_info dune.coriolismapinfo) -> void
|
|
-- oid: 58178 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.coriolis_cleanup_farm(in_server_info dune.serverinfo, in_map_info dune.coriolismapinfo)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM lore_pickups_temporary;
|
|
DELETE FROM consumed_temporary_per_player_lore;
|
|
UPDATE player_state SET is_coriolis_processed = FALSE;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- coriolis_cleanup_partition(in_server_info dune.serverinfo, in_map_info dune.coriolismapinfo) -> void
|
|
-- oid: 58179 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.coriolis_cleanup_partition(in_server_info dune.serverinfo, in_map_info dune.coriolismapinfo)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF in_map_info.is_outside_shieldwall
|
|
THEN
|
|
PERFORM delete_actors_and_respawns_on_server(in_server_info, (in_map_info).vehicle_classes_spawned_on_map, TRUE);
|
|
|
|
update player_state set life_state='DeadByCoriolis'
|
|
from actors
|
|
where player_state.player_pawn_id=actors.id AND server_info_match(actors, in_server_info) and
|
|
not exists (SELECT 1 FROM actor_state WHERE actor_state.actor_id = player_state.player_pawn_id AND actor_state.state = 'Travel');
|
|
|
|
-- Move players that died to Hagga Basin in their respective dimension and partition
|
|
UPDATE actors
|
|
SET
|
|
map = 'HaggaBasin',
|
|
dimension_index = player_state.return_dimension_index,
|
|
partition_id = (
|
|
SELECT world_partition.partition_id
|
|
FROM world_partition
|
|
WHERE player_state.return_dimension_index = world_partition.dimension_index AND world_partition.map = 'Survival_1'
|
|
)
|
|
FROM player_state
|
|
WHERE
|
|
(player_state.player_controller_id = actors.id OR player_state.player_pawn_id = actors.id OR player_state.player_state_id = actors.id) AND
|
|
server_info_match(actors, in_server_info) AND
|
|
NOT EXISTS (SELECT 1 FROM actor_state WHERE actor_state.actor_id = player_state.player_pawn_id AND actor_state.state = 'Travel');
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- coriolis_update_seed(in_server_info dune.serverinfo, in_new_coriolis_seed integer, in_map_info dune.coriolismapinfo) -> void
|
|
-- oid: 58180 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.coriolis_update_seed(in_server_info dune.serverinfo, in_new_coriolis_seed integer, in_map_info dune.coriolismapinfo)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
old_farm_coriolis_seed Integer;
|
|
old_map_coriolis_seed Integer;
|
|
old_partition_coriolis_seed Integer;
|
|
BEGIN
|
|
LOCK TABLE world_farm_reset_seed, world_map_reset_seed, world_partition_reset_seed IN EXCLUSIVE MODE;
|
|
|
|
SELECT INTO old_farm_coriolis_seed world_reset_seed FROM world_farm_reset_seed WHERE onerow_id = TRUE limit 1;
|
|
UPDATE world_farm_reset_seed SET world_reset_seed = in_new_coriolis_seed WHERE onerow_id = TRUE;
|
|
|
|
SELECT INTO old_map_coriolis_seed world_reset_seed FROM world_map_reset_seed WHERE map = in_server_info.map limit 1;
|
|
INSERT INTO world_map_reset_seed (map, world_reset_seed) Values(in_server_info.map, in_new_coriolis_seed)
|
|
ON CONFLICT(map) DO
|
|
UPDATE SET world_reset_seed = in_new_coriolis_seed;
|
|
|
|
SELECT INTO old_partition_coriolis_seed world_reset_seed FROM world_partition_reset_seed WHERE partition_id = in_server_info.partition_id limit 1;
|
|
IF in_server_info.partition_id IS NOT NULL
|
|
THEN
|
|
INSERT INTO world_partition_reset_seed (partition_id, world_reset_seed) Values(in_server_info.partition_id, in_new_coriolis_seed)
|
|
ON CONFLICT(partition_id) DO
|
|
UPDATE SET world_reset_seed = in_new_coriolis_seed;
|
|
END IF;
|
|
|
|
IF old_farm_coriolis_seed IS NULL OR old_farm_coriolis_seed <> in_new_coriolis_seed
|
|
THEN
|
|
PERFORM coriolis_cleanup_farm(in_server_info, in_map_info);
|
|
END IF;
|
|
|
|
IF in_map_info.is_affected_by_coriolis
|
|
THEN
|
|
IF old_map_coriolis_seed IS NULL OR old_map_coriolis_seed <> in_new_coriolis_seed
|
|
THEN
|
|
PERFORM corilis_cleanup_map(in_server_info, in_map_info);
|
|
END IF;
|
|
|
|
IF (in_server_info.partition_id IS NOT NULL AND (old_partition_coriolis_seed IS NULL OR old_partition_coriolis_seed <> in_new_coriolis_seed)) OR
|
|
(old_map_coriolis_seed IS NULL OR old_map_coriolis_seed <> in_new_coriolis_seed)
|
|
THEN
|
|
PERFORM coriolis_cleanup_partition(in_server_info, in_map_info);
|
|
END IF;
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- create_event_log_partition() -> trigger
|
|
-- oid: 58181 kind: FUNCTION category: event_log
|
|
|
|
CREATE OR REPLACE FUNCTION dune.create_event_log_partition()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
CALL create_event_log_partition_table('event_log', NEW.partition_id);
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- create_event_log_partition_table(IN table_name text, IN partition_id bigint) -> void
|
|
-- oid: 58182 kind: PROCEDURE category: event_log
|
|
|
|
CREATE OR REPLACE PROCEDURE dune.create_event_log_partition_table(IN table_name text, IN partition_id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $procedure$
|
|
DECLARE
|
|
start_range BIGINT;
|
|
end_range BIGINT;
|
|
partition_table_name TEXT;
|
|
BEGIN
|
|
start_range := partition_id;
|
|
end_range := partition_id + 1;
|
|
partition_table_name := format('%s_p%s', table_name, partition_id);
|
|
|
|
EXECUTE format('
|
|
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
FOR VALUES FROM (%s) TO (%s);
|
|
', partition_table_name, table_name, start_range, end_range);
|
|
|
|
END;
|
|
$procedure$
|
|
|
|
|
|
-- create_guild(in_player_id bigint, in_neutral_faction smallint, in_guild_name text, in_guild_desc text, in_max_guild_count_per_player integer, OUT out_guild_id bigint, OUT out_success boolean, OUT out_fail_reason dune.guildcreatefailreason) -> record
|
|
-- oid: 58183 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.create_guild(in_player_id bigint, in_neutral_faction smallint, in_guild_name text, in_guild_desc text, in_max_guild_count_per_player integer, OUT out_guild_id bigint, OUT out_success boolean, OUT out_fail_reason dune.guildcreatefailreason)
|
|
RETURNS record
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
guild_count integer;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
IF EXISTS (SELECT 1 FROM guilds WHERE guild_name ILIKE in_guild_name) THEN
|
|
out_guild_id := 0;
|
|
out_success := FALSE;
|
|
out_fail_reason := 'NameAlreadyTaken'::GuildCreateFailReason; -- 1 represents NAME_ALREADY_EXISTS
|
|
RETURN;
|
|
END IF;
|
|
|
|
-- we need to check if the player is already part of max amount of guilds before being able to add them
|
|
SELECT INTO guild_count COUNT(*) FROM guild_members WHERE player_id = in_player_id;
|
|
IF guild_count >= in_max_guild_count_per_player THEN
|
|
out_guild_id := 0;
|
|
out_success := FALSE;
|
|
out_fail_reason := 'QueryError'::GuildCreateFailReason;
|
|
RETURN;
|
|
END IF;
|
|
|
|
INSERT INTO guilds("guild_id", "guild_name", "guild_faction", "guild_description") VALUES(DEFAULT, in_guild_name, in_neutral_faction , in_guild_desc) RETURNING "guild_id" INTO out_guild_id;
|
|
INSERT INTO guild_members("player_id", "guild_id", "role_id") VALUES(in_player_id, out_guild_id, 100);
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('add_player#{"PlayerId" : %s , "PlayerFactionId" : %s, "GuildId" : %s, "RoleId" : 100, "ShouldClearInvites" : 0}', in_player_id, get_player_faction(in_player_id, in_neutral_faction), out_guild_id));
|
|
|
|
out_success := TRUE;
|
|
out_fail_reason := 'None'::GuildCreateFailReason;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- create_or_update_tutorial_entry(in_player_id bigint, in_tutorial_id smallint, in_tutorial_state smallint) -> void
|
|
-- oid: 58184 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.create_or_update_tutorial_entry(in_player_id bigint, in_tutorial_id smallint, in_tutorial_state smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO tutorial_per_player("player_id", "tutorial_id", "tutorial_state") VALUES(in_player_id, in_tutorial_id, in_tutorial_state)
|
|
ON CONFLICT (player_id, tutorial_id) DO UPDATE SET "player_id" = in_player_id, "tutorial_id" = in_tutorial_id, "tutorial_state" = in_tutorial_state
|
|
WHERE tutorial_per_player.player_id = in_player_id AND tutorial_per_player.tutorial_id = in_tutorial_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- create_server_player_access_codes(in_account_id bigint, in_access_code integer, in_access_code_type integer, in_is_resettable boolean) -> void
|
|
-- oid: 58185 kind: FUNCTION category: server
|
|
|
|
CREATE OR REPLACE FUNCTION dune.create_server_player_access_codes(in_account_id bigint, in_access_code integer, in_access_code_type integer, in_is_resettable boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO player_access_codes(account_id, access_code, access_code_type,is_resettable)
|
|
VALUES(in_account_id, in_access_code, in_access_code_type, in_is_resettable);
|
|
END; $function$
|
|
|
|
|
|
-- create_sinkchart_for_map_area_id(in_item_id bigint, in_creator_id bigint, in_map_name text, in_area_id smallint) -> integer
|
|
-- oid: 58186 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.create_sinkchart_for_map_area_id(in_item_id bigint, in_creator_id bigint, in_map_name text, in_area_id smallint)
|
|
RETURNS integer
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
sinkchart_marker_ids BIGINT[];
|
|
sinkchart_array_length INT;
|
|
BEGIN
|
|
-- Aggregate marker hash IDs into an array based on the conditions
|
|
SELECT ARRAY_AGG(markers.marker_hash_id) INTO sinkchart_marker_ids
|
|
FROM player_markers,
|
|
markers JOIN map_names USING(map_name_id)
|
|
WHERE player_markers.player_id = in_creator_id
|
|
AND map_names.map_name = in_map_name
|
|
AND player_markers.map_name_id = markers.map_name_id
|
|
AND player_markers.marker_hash_id = markers.marker_hash_id
|
|
AND markers.area_id = in_area_id
|
|
AND (player_markers.discovery_level = 2 OR player_markers.discovery_level = 3); -- 'EMarkerDiscoveryLevel::Mysterious' OR 'EMarkerDiscoveryLevel::Discovered'
|
|
|
|
-- Check if is NOT NULL before proceeding with the INSERT
|
|
IF array_length(sinkchart_marker_ids, 1) IS NOT NULL THEN
|
|
INSERT INTO sinkcharts (item_id, marker_hash_ids)
|
|
VALUES (in_item_id, sinkchart_marker_ids)
|
|
RETURNING array_length(marker_hash_ids, 1) INTO sinkchart_array_length;
|
|
|
|
RETURN sinkchart_array_length;
|
|
ELSE
|
|
RETURN 0;
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- debug_add_test_table_data(in_entry text) -> void
|
|
-- oid: 58187 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_add_test_table_data(in_entry text)
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
insert into debug_test_table("entry") VALUES (in_entry);
|
|
$function$
|
|
|
|
|
|
-- debug_collect_test_table_data() -> SETOF text
|
|
-- oid: 58188 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_collect_test_table_data()
|
|
RETURNS SETOF text
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select entry from debug_test_table;
|
|
$function$
|
|
|
|
|
|
-- debug_echo(in_text text, in_notices text[]) -> text
|
|
-- oid: 58189 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_echo(in_text text, in_notices text[])
|
|
RETURNS text
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
perform debug_raise_notices(in_notices);
|
|
return in_text;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- debug_get_coriolis_seeds() -> TABLE(farm_seed integer, map_names text[], map_seeds integer[], partitions_ids bigint[], partitions_map text[], partitions_seeds integer[])
|
|
-- oid: 58190 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_get_coriolis_seeds()
|
|
RETURNS TABLE(farm_seed integer, map_names text[], map_seeds integer[], partitions_ids bigint[], partitions_map text[], partitions_seeds integer[])
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
RETURN QUERY
|
|
WITH
|
|
map_seeds as (
|
|
SELECT array_agg(map_name) as map_name, array_agg(seed) as seed
|
|
FROM (
|
|
SELECT COALESCE(map_seed.map, partition.map) AS map_name, COALESCE(map_seed.world_reset_seed, -1) AS seed
|
|
FROM world_map_reset_seed AS map_seed FULL JOIN world_partition as partition ON map_seed.map = partition.map
|
|
GROUP BY map_seed.map, partition.map, map_seed.world_reset_seed
|
|
ORDER BY map_name ASC
|
|
) as maps_temp
|
|
|
|
),
|
|
partitions_seeds as (
|
|
SELECT array_agg(partition_id) as partition_id, array_agg(map_name) as map_name, array_agg(seed) as seed
|
|
FROM (
|
|
SELECT partition.partition_id as partition_id, partition.map as map_name, COALESCE(partition_seed.world_reset_seed, -1) AS seed
|
|
FROM world_partition_reset_seed AS partition_seed FULL JOIN world_partition as partition ON partition_seed.partition_id = partition.partition_id
|
|
GROUP BY partition.map, partition.partition_id, partition_seed.world_reset_seed
|
|
ORDER BY partition.partition_id ASC
|
|
) as partitions_temp
|
|
)
|
|
SELECT
|
|
COALESCE(world_reset_seed, -1),
|
|
COALESCE(map_seeds.map_name, array[]::TEXT[]),
|
|
COALESCE(map_seeds.seed, array[]::Integer[]),
|
|
COALESCE(partitions_seeds.partition_id, array[]::BigInt[]),
|
|
COALESCE(partitions_seeds.map_name, array[]::TEXT[]),
|
|
COALESCE(partitions_seeds.seed, array[]::Integer[])
|
|
FROM
|
|
world_farm_reset_seed,
|
|
map_seeds,
|
|
partitions_seeds;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- debug_raise_exception(in_exception text, in_notices text[]) -> void
|
|
-- oid: 58191 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_raise_exception(in_exception text, in_notices text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
perform debug_raise_notices(in_notices);
|
|
RAISE EXCEPTION '%', in_exception;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- debug_raise_notices(in_notices text[]) -> void
|
|
-- oid: 58192 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_raise_notices(in_notices text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF array_length(in_notices, 1) IS NOT NULL THEN
|
|
FOR i IN 0..array_length(in_notices, 1)-1
|
|
LOOP
|
|
RAISE NOTICE '%', in_notices[i];
|
|
END LOOP;
|
|
END IF;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- debug_reset_test_table() -> void
|
|
-- oid: 58193 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_reset_test_table()
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
truncate debug_test_table;
|
|
$function$
|
|
|
|
|
|
-- debug_set_farm_seed(in_new_coriolis_seed integer) -> void
|
|
-- oid: 58194 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_set_farm_seed(in_new_coriolis_seed integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
UPDATE world_farm_reset_seed SET world_reset_seed = in_new_coriolis_seed WHERE onerow_id = TRUE;
|
|
|
|
UPDATE world_map_reset_seed SET world_reset_seed = in_new_coriolis_seed;
|
|
INSERT INTO world_map_reset_seed SELECT map, in_new_coriolis_seed FROM world_partition GROUP BY map
|
|
ON CONFLICT(map) DO
|
|
UPDATE SET world_reset_seed = in_new_coriolis_seed;
|
|
|
|
UPDATE world_partition_reset_seed SET world_reset_seed = in_new_coriolis_seed;
|
|
INSERT INTO world_partition_reset_seed SELECT partition_id, in_new_coriolis_seed FROM world_partition GROUP BY partition_id
|
|
ON CONFLICT(partition_id) DO
|
|
UPDATE SET world_reset_seed = in_new_coriolis_seed;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- debug_set_map_seed(in_map text, in_new_coriolis_seed integer) -> void
|
|
-- oid: 58195 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_set_map_seed(in_map text, in_new_coriolis_seed integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
INSERT INTO world_map_reset_seed (map, world_reset_seed) Values(in_server_info.map, in_new_coriolis_seed)
|
|
ON CONFLICT(map) DO
|
|
UPDATE SET world_reset_seed = in_new_coriolis_seed;
|
|
|
|
UPDATE world_partition_reset_seed SET world_reset_seed = in_new_coriolis_seed WHERE map = in_map;
|
|
INSERT INTO world_partition_reset_seed SELECT partition_id, in_new_coriolis_seed FROM world_partition WHERE map = in_map GROUP BY partition_id
|
|
ON CONFLICT(partition_id) DO
|
|
UPDATE SET world_reset_seed = in_new_coriolis_seed;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- debug_set_partition_seed(in_partition_id bigint, in_new_coriolis_seed integer) -> void
|
|
-- oid: 58196 kind: FUNCTION category: debug
|
|
|
|
CREATE OR REPLACE FUNCTION dune.debug_set_partition_seed(in_partition_id bigint, in_new_coriolis_seed integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
INSERT INTO world_partition_reset_seed (partition_id, world_reset_seed) Values(in_server_info.partition_id, in_new_coriolis_seed)
|
|
ON CONFLICT(partition_id) DO
|
|
UPDATE SET world_reset_seed = in_new_coriolis_seed;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- decrypt_user_data(in_encrypted_data bytea) -> text
|
|
-- oid: 58197 kind: FUNCTION category: encryption
|
|
|
|
CREATE OR REPLACE FUNCTION dune.decrypt_user_data(in_encrypted_data bytea)
|
|
RETURNS text
|
|
LANGUAGE sql
|
|
IMMUTABLE
|
|
AS $function$select convert_from(in_encrypted_data, 'utf8');$function$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- delete_actor_states_travel(in_actor_id bigint) -> void
|
|
-- oid: 58199 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_actor_states_travel(in_actor_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
WITH
|
|
traveling_actor_ids AS (
|
|
SELECT t.id FROM get_traveling_non_player_actor_ids(in_actor_id) AS t
|
|
)
|
|
DELETE FROM actor_state WHERE (actor_id IN (SELECT t.id FROM traveling_actor_ids AS t(id)) OR actor_id = in_actor_id) AND state = 'Travel';
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- delete_actors(in_ids bigint[]) -> void
|
|
-- oid: 58200 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_actors(in_ids bigint[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM actors WHERE id = ANY(in_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_actors_and_respawns_on_server(in_server_info dune.serverinfo, in_vehicle_classes_spawned_on_map text[], in_allow_vehicle_recovery boolean) -> void
|
|
-- oid: 58201 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_actors_and_respawns_on_server(in_server_info dune.serverinfo, in_vehicle_classes_spawned_on_map text[], in_allow_vehicle_recovery boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
WITH actors_to_delete AS (
|
|
SELECT a.id
|
|
FROM actors a
|
|
LEFT JOIN actor_state s ON a.id = s.actor_id
|
|
WHERE owner_account_id IS NULL
|
|
AND s.state IS DISTINCT FROM 'Travel'
|
|
AND s.state IS DISTINCT FROM 'VehicleBackup'
|
|
AND s.state IS DISTINCT FROM 'VehicleRecovery'
|
|
AND server_info_match(a, in_server_info)
|
|
AND (
|
|
-- Actors that are not vehicles should always be deleted
|
|
NOT EXISTS (SELECT 1 FROM vehicles v WHERE v.id = a.id)
|
|
-- Only vehicles that are allowed to be spawned on this map should be deleted
|
|
OR in_vehicle_classes_spawned_on_map IS NULL -- If the list is NULL all vehicles are allowed
|
|
OR a.class = ANY(in_vehicle_classes_spawned_on_map) -- Vehicle type is explicitly allowed on this map
|
|
)
|
|
ORDER BY a.id FOR UPDATE OF a
|
|
),
|
|
vehicles_to_recover AS (
|
|
SELECT COALESCE(ARRAY_AGG(v.id), ARRAY[]::BIGINT[]) AS ids FROM actors_to_delete a JOIN vehicles v ON (a.id = v.id)
|
|
WHERE in_allow_vehicle_recovery
|
|
),
|
|
recovered_vehicles AS (
|
|
SELECT ids, store_recovered_vehicles_wiped_before_spawn(ids) FROM vehicles_to_recover
|
|
)
|
|
DELETE FROM actors a USING recovered_vehicles rv
|
|
WHERE a.id = ANY(SELECT id FROM actors_to_delete)
|
|
AND NOT a.id = ANY(rv.ids);
|
|
|
|
with
|
|
deleted_ids as (
|
|
DELETE from player_respawn_locations
|
|
WHERE map = in_server_info.map AND dimension = in_server_info.dimension_index
|
|
returning id
|
|
)
|
|
update player_state set pending_respawn_location_id=null
|
|
where pending_respawn_location_id in (select * from deleted_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_all_dungeon_completions(in_dungeon_id text) -> void
|
|
-- oid: 58202 kind: FUNCTION category: dungeon
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_all_dungeon_completions(in_dungeon_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
DELETE FROM dungeon_completion WHERE dungeon_id = in_dungeon_id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- delete_all_dungeon_completions_by_player(in_dungeon_id text, in_player_id bigint, in_keep_completion_for_other_players boolean) -> void
|
|
-- oid: 58203 kind: FUNCTION category: dungeon
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_all_dungeon_completions_by_player(in_dungeon_id text, in_player_id bigint, in_keep_completion_for_other_players boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
DELETE FROM dungeon_completion WHERE
|
|
NOT in_keep_completion_for_other_players AND
|
|
dungeon_id = in_dungeon_id AND
|
|
completion_id IN (SELECT completion_id FROM dungeon_completion_players WHERE player_id = in_player_id);
|
|
|
|
DELETE FROM dungeon_completion_players
|
|
WHERE
|
|
in_keep_completion_for_other_players AND
|
|
player_id = in_player_id AND
|
|
completion_id IN (SELECT completion_id FROM dungeon_completion WHERE dungeon_id = in_dungeon_id);
|
|
end
|
|
$function$
|
|
|
|
|
|
-- delete_all_dungeon_completions_for_all_dungeons_by_player(in_player_id bigint, in_keep_completion_for_other_players boolean) -> void
|
|
-- oid: 58204 kind: FUNCTION category: dungeon
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_all_dungeon_completions_for_all_dungeons_by_player(in_player_id bigint, in_keep_completion_for_other_players boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
DELETE FROM dungeon_completion WHERE
|
|
NOT in_keep_completion_for_other_players AND
|
|
completion_id IN (SELECT completion_id FROM dungeon_completion_players WHERE player_id = in_player_id);
|
|
|
|
DELETE FROM dungeon_completion_players WHERE in_keep_completion_for_other_players AND player_id = in_player_id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- delete_all_inactive_farms() -> void
|
|
-- oid: 58205 kind: FUNCTION category: farm
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_all_inactive_farms()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM farm_state WHERE server_id NOT IN (SELECT * FROM active_server_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_all_journey_story_nodes(in_account_id bigint) -> void
|
|
-- oid: 58206 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_all_journey_story_nodes(in_account_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM journey_story_node WHERE account_id = in_account_id;
|
|
END $function$
|
|
|
|
|
|
-- delete_all_static_shifting_sand() -> void
|
|
-- oid: 58207 kind: FUNCTION category: shifting_sand
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_all_static_shifting_sand()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
TRUNCATE shiftingsands_data;
|
|
END $function$
|
|
|
|
|
|
-- delete_all_tutorial_entries(in_player_id bigint) -> void
|
|
-- oid: 58208 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_all_tutorial_entries(in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM tutorial_per_player WHERE tutorial_per_player.player_id = in_player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_building_blueprint(in_building_item_id bigint) -> void
|
|
-- oid: 58209 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_building_blueprint(in_building_item_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM building_blueprints WHERE id = in_building_item_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_character(in_actor_id bigint) -> void
|
|
-- oid: 58210 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_character(in_actor_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM actors WHERE id = in_actor_id;
|
|
DELETE FROM properties WHERE object_id = in_actor_id;
|
|
DELETE FROM fgl_data WHERE object_id = in_actor_id;
|
|
DELETE FROM actor_transform WHERE actor_id = in_actor_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_crafted_map(in_item_id bigint) -> void
|
|
-- oid: 58211 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_crafted_map(in_item_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM crafted_maps WHERE item_id = in_item_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_dialogue_data(in_player_controller_id bigint) -> void
|
|
-- oid: 58212 kind: FUNCTION category: dialogue
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_dialogue_data(in_player_controller_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM dialogue_met_npcs
|
|
WHERE player_id = in_player_controller_id;
|
|
|
|
DELETE FROM dialogue_taken_nodes
|
|
WHERE player_id = in_player_controller_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_inventory_item(in_item_id bigint, in_count bigint) -> bigint
|
|
-- oid: 58213 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_inventory_item(in_item_id bigint, in_count bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
remaining_stack_size BIGINT;
|
|
BEGIN
|
|
SELECT INTO STRICT remaining_stack_size stack_size FROM items WHERE id = in_item_id;
|
|
|
|
remaining_stack_size := remaining_stack_size - in_count;
|
|
|
|
IF remaining_stack_size < 0 THEN
|
|
RETURN NULL;
|
|
END IF;
|
|
|
|
IF remaining_stack_size > 0 THEN
|
|
UPDATE items SET stack_size = remaining_stack_size WHERE id = in_item_id;
|
|
ELSE
|
|
PERFORM delete_item(in_item_id);
|
|
END IF;
|
|
RETURN remaining_stack_size;
|
|
END $function$
|
|
|
|
|
|
-- delete_item(in_id bigint) -> void
|
|
-- oid: 58214 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_item(in_id bigint)
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
DELETE FROM items i
|
|
USING inventories inv
|
|
WHERE i.inventory_id = inv.id
|
|
AND i.id = in_id
|
|
RETURNING _add_item_delete_log(
|
|
i.id,
|
|
inv.id,
|
|
i.template_id
|
|
);
|
|
$function$
|
|
|
|
|
|
-- delete_items(in_ids bigint[]) -> void
|
|
-- oid: 58215 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_items(in_ids bigint[])
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
DELETE FROM items i
|
|
USING inventories inv
|
|
WHERE i.inventory_id = inv.id
|
|
AND i.id = ANY (in_ids)
|
|
RETURNING _add_item_delete_log(
|
|
i.id,
|
|
inv.id,
|
|
i.template_id
|
|
);
|
|
$function$
|
|
|
|
|
|
-- delete_items_from_actor(in_actor_id bigint) -> void
|
|
-- oid: 58216 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_items_from_actor(in_actor_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM delete_items(
|
|
(
|
|
SELECT array_agg(i.id)
|
|
FROM items i
|
|
JOIN inventories inv ON inv.id = i.inventory_id
|
|
WHERE inv.actor_id = in_actor_id
|
|
)
|
|
);
|
|
END $function$
|
|
|
|
|
|
-- delete_journey_story_ids(story_ids text[]) -> void
|
|
-- oid: 58217 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_journey_story_ids(story_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM journey_story_node
|
|
WHERE story_node_id = ANY(story_ids);
|
|
|
|
DELETE FROM journey_story_node_cooldown
|
|
WHERE story_node_id = ANY(story_ids);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- delete_journey_story_node(in_account_id bigint, in_story_node_id text) -> void
|
|
-- oid: 58218 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_journey_story_node(in_account_id bigint, in_story_node_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM journey_story_node WHERE account_id = in_account_id AND story_node_id = in_story_node_id;
|
|
END $function$
|
|
|
|
|
|
-- delete_journey_story_nodes_for_group_for_player(in_account_id bigint, in_reset_group dune.journeystoryresetgroup) -> void
|
|
-- oid: 58219 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_journey_story_nodes_for_group_for_player(in_account_id bigint, in_reset_group dune.journeystoryresetgroup)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM journey_story_node_cooldown
|
|
WHERE story_node_id IN (
|
|
SELECT story_node_id
|
|
FROM journey_story_node a
|
|
WHERE a.account_id = in_account_id AND a.reset_group = in_reset_group
|
|
)
|
|
AND account_id = in_account_id;
|
|
|
|
DELETE FROM journey_story_node
|
|
WHERE reset_group = in_reset_group AND account_id = in_account_id;
|
|
END $function$
|
|
|
|
|
|
-- delete_journey_story_nodes_for_player(in_player_id text, in_story_node_ids text[]) -> void
|
|
-- oid: 58220 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_journey_story_nodes_for_player(in_player_id text, in_story_node_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM journey_story_node
|
|
WHERE story_node_id = ANY(in_story_node_ids)
|
|
AND account_id IN (
|
|
SELECT id
|
|
FROM accounts a
|
|
WHERE a.user = in_player_id
|
|
);
|
|
|
|
DELETE FROM journey_story_node_cooldown
|
|
WHERE story_node_id = ANY(in_story_node_ids)
|
|
AND account_id IN (
|
|
SELECT id
|
|
FROM accounts a
|
|
WHERE a.user = in_player_id
|
|
);
|
|
END $function$
|
|
|
|
|
|
-- delete_journey_story_nodes_for_player_account(in_account_id bigint, in_story_node_ids text[]) -> void
|
|
-- oid: 58221 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_journey_story_nodes_for_player_account(in_account_id bigint, in_story_node_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM journey_story_node
|
|
WHERE story_node_id = ANY(in_story_node_ids)
|
|
AND account_id = in_account_id;
|
|
|
|
DELETE FROM journey_story_node_cooldown
|
|
WHERE story_node_id = ANY(in_story_node_ids)
|
|
AND account_id = in_account_id;
|
|
END $function$
|
|
|
|
|
|
-- delete_map_markers(in_dimension_index integer, in_map_name text, in_player_marker_data dune.deleteplayermarkerdata[]) -> void
|
|
-- oid: 58222 kind: FUNCTION category: markers
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_map_markers(in_dimension_index integer, in_map_name text, in_player_marker_data dune.deleteplayermarkerdata[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
WITH player_hash_ids AS (SELECT player_id, marker_hash_ids FROM UNNEST(in_player_marker_data)),
|
|
player_markers_to_delete AS (
|
|
SELECT player_markers.* FROM player_hash_ids, player_markers JOIN map_names USING(map_name_id)
|
|
WHERE (player_markers.dimension_index = in_dimension_index OR player_markers.dimension_index = -1)
|
|
AND map_names.map_name = in_map_name
|
|
AND player_markers.player_id = player_hash_ids.player_id
|
|
AND player_markers.marker_hash_id = ANY(player_hash_ids.marker_hash_ids)
|
|
ORDER BY player_markers.player_id, player_markers.marker_hash_id, player_markers.dimension_index FOR UPDATE -- Ordering for deadlock avoidance
|
|
)
|
|
DELETE FROM player_markers USING player_markers_to_delete
|
|
WHERE player_markers.dimension_index = player_markers_to_delete.dimension_index
|
|
AND player_markers.map_name_id = player_markers_to_delete.map_name_id
|
|
AND player_markers.player_id = player_markers_to_delete.player_id
|
|
AND player_markers.marker_hash_id = player_markers_to_delete.marker_hash_id;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- delete_markers_by_id(in_marker_ids integer[]) -> void
|
|
-- oid: 58223 kind: FUNCTION category: markers
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_markers_by_id(in_marker_ids integer[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM markers WHERE marker_hash_id = ANY (in_marker_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_markers_by_static_location_key(p_location_key text) -> void
|
|
-- oid: 58224 kind: FUNCTION category: markers
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_markers_by_static_location_key(p_location_key text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM markers WHERE (payload #>> '{LocationKey}') = p_location_key;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- delete_markers_for_all_players(in_marker_types_to_keep text[], in_map text) -> void
|
|
-- oid: 58225 kind: FUNCTION category: markers
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_markers_for_all_players(in_marker_types_to_keep text[], in_map text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
-- Lock markers matching query
|
|
WITH affected_markers AS (
|
|
SELECT * FROM markers JOIN map_names USING(map_name_id)
|
|
WHERE (in_map IS NULL OR map_names.map_name = in_map) AND NOT (marker).marker_type = ANY(in_marker_types_to_keep)
|
|
ORDER BY marker_hash_id, dimension_index, map_name_id FOR UPDATE -- Ordering to avoid deadlocks
|
|
),
|
|
-- Lock player_markers to be deleted on cascade
|
|
referencing_player_markers AS (
|
|
SELECT player_markers.* FROM player_markers, affected_markers
|
|
WHERE affected_markers.marker_hash_id = player_markers.marker_hash_id
|
|
AND affected_markers.dimension_index = player_markers.dimension_index
|
|
AND affected_markers.map_name_id = player_markers.map_name_id
|
|
ORDER BY player_id, player_markers.marker_hash_id, player_markers.dimension_index, player_markers.map_name_id FOR UPDATE -- Ordering to avoid deadlocks
|
|
)
|
|
-- Delete markers
|
|
DELETE FROM markers USING affected_markers
|
|
WHERE affected_markers.marker_hash_id = markers.marker_hash_id
|
|
AND affected_markers.dimension_index = markers.dimension_index
|
|
AND affected_markers.map_name_id = markers.map_name_id;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- delete_markers_return_actor_ids(in_dimension_index integer, in_map_name text, in_marker_ids integer[]) -> TABLE(actor_id bigint, marker_id integer)
|
|
-- oid: 58226 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_markers_return_actor_ids(in_dimension_index integer, in_map_name text, in_marker_ids integer[])
|
|
RETURNS TABLE(actor_id bigint, marker_id integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
-- Lock markers matching query
|
|
WITH affected_markers AS (
|
|
SELECT * FROM markers JOIN map_names USING(map_name_id)
|
|
WHERE (dimension_index = in_dimension_index OR dimension_index = -1)
|
|
AND map_names.map_name = in_map_name
|
|
AND marker_hash_id = ANY(in_marker_ids)
|
|
ORDER BY marker_hash_id, dimension_index FOR UPDATE -- Ordering to avoid deadlocks
|
|
),
|
|
-- Lock player_markers to be deleted on cascade
|
|
referencing_player_markers AS (
|
|
SELECT player_id, player_markers.marker_hash_id FROM player_markers, affected_markers
|
|
WHERE affected_markers.marker_hash_id = player_markers.marker_hash_id
|
|
AND affected_markers.dimension_index = player_markers.dimension_index
|
|
AND affected_markers.map_name_id = player_markers.map_name_id
|
|
ORDER BY player_id, player_markers.marker_hash_id, player_markers.dimension_index FOR UPDATE -- Ordering to avoid deadlocks
|
|
),
|
|
-- Delete markers
|
|
deleted_markers AS (
|
|
DELETE FROM markers USING affected_markers
|
|
WHERE affected_markers.marker_hash_id = markers.marker_hash_id
|
|
AND affected_markers.dimension_index = markers.dimension_index
|
|
AND affected_markers.map_name_id = markers.map_name_id
|
|
)
|
|
SELECT * FROM referencing_player_markers;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_mnemonic_recall_lesson(in_account_id bigint, in_lesson_id text) -> void
|
|
-- oid: 58227 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_mnemonic_recall_lesson(in_account_id bigint, in_lesson_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM mnemonic_recall WHERE account_id = in_account_id AND lesson_id = in_lesson_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_mnemonic_recall_lesson_all(in_account_id bigint) -> void
|
|
-- oid: 58228 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_mnemonic_recall_lesson_all(in_account_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM mnemonic_recall WHERE account_id = in_account_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_server_player_access_codes(in_account_id bigint, in_access_code integer, in_access_code_type integer) -> void
|
|
-- oid: 58229 kind: FUNCTION category: server
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_server_player_access_codes(in_account_id bigint, in_access_code integer, in_access_code_type integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM player_access_codes
|
|
WHERE account_id = in_account_id
|
|
AND access_code = in_access_code
|
|
AND access_code_type = in_access_code_type;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_spawner(in_map text, in_name text, in_dimension_index integer) -> void
|
|
-- oid: 58230 kind: FUNCTION category: spawner
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_spawner(in_map text, in_name text, in_dimension_index integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM actor_spawners WHERE map = in_map AND name = in_name AND dimension_index = in_dimension_index;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- delete_static_location_markers(p_location_keys text[]) -> void
|
|
-- oid: 58231 kind: FUNCTION category: markers
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_static_location_markers(p_location_keys text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM markers WHERE (payload #>> '{LocationKey}') = ANY(p_location_keys);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- delete_world_partition_by_map_id(in_map_id text) -> void
|
|
-- oid: 58232 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.delete_world_partition_by_map_id(in_map_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM world_partition WHERE "map"=in_map_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- demote_guild_member(in_guild_id bigint, in_player_id bigint, in_new_role smallint) -> void
|
|
-- oid: 58233 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.demote_guild_member(in_guild_id bigint, in_player_id bigint, in_new_role smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- check if new admin is actualy in guild
|
|
IF NOT EXISTS(SELECT FROM guild_members WHERE player_id = in_player_id AND guild_id = in_guild_id) THEN
|
|
RAISE EXCEPTION 'Trying to demote player not in guild %.', in_player_id;
|
|
END IF;
|
|
|
|
IF is_player_guild_admin(in_player_id, in_guild_id) THEN
|
|
RAISE EXCEPTION 'Trying to demote admin. promote a member to admin instead.';
|
|
END IF;
|
|
|
|
if in_new_role = 100 THEN
|
|
RAISE EXCEPTION 'Trying to demote to admin.';
|
|
END IF;
|
|
|
|
-- set new player to new role
|
|
UPDATE guild_members SET role_id = in_new_role WHERE player_id = in_player_id AND guild_id = in_guild_id;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('demote_player#{"PlayerId" : %s , "GuildId" : %s, "NewRole" : %s}', in_player_id, in_guild_id, in_new_role));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- determine_partition_label(in_map text, in_dimension_index integer, in_label text, in_allow_overwrite boolean, in_partition_id bigint) -> text
|
|
-- oid: 58234 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.determine_partition_label(in_map text, in_dimension_index integer, in_label text DEFAULT NULL::text, in_allow_overwrite boolean DEFAULT true, in_partition_id bigint DEFAULT NULL::bigint)
|
|
RETURNS text
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result_label TEXT := in_label;
|
|
tmp_count INTEGER;
|
|
tmp_box_max_x TEXT;
|
|
tmp_box_max_y TEXT;
|
|
tmp_box_min_x TEXT;
|
|
tmp_box_min_y TEXT;
|
|
BEGIN
|
|
-- If label is provided and we don't want to overwrite, return it
|
|
IF result_label IS NOT NULL AND in_allow_overwrite = FALSE THEN
|
|
RETURN result_label;
|
|
END IF;
|
|
|
|
CASE in_map
|
|
WHEN 'SH_HarkoVillage' THEN return 'HarkoVillage' || '_' || in_dimension_index;
|
|
WHEN 'SH_Arrakeen' THEN return 'Arrakeen' || '_' || in_dimension_index;
|
|
WHEN 'SH_FallenLight' THEN return 'FallenLight' || '_' || in_dimension_index;
|
|
WHEN 'CB_Story_Hephaestus' THEN return 'WreckOfHephaestus' || '_' || in_dimension_index;
|
|
WHEN 'CB_Story_Ecolab_Carthag' THEN return 'BeneathCarthag' || '_' || in_dimension_index;
|
|
WHEN 'CB_SurvivalChallenge_Station_15' THEN return 'Station15' || '_' || in_dimension_index;
|
|
WHEN 'CB_Story_WaterFatManor' THEN return 'WaterFat' || '_' || in_dimension_index;
|
|
WHEN 'Story_ProcesVerbal' THEN return 'ProcesVerbal' || '_' || in_dimension_index;
|
|
WHEN 'DLC_Story_LostHarvest' THEN return 'LostHarvest' || '_' || in_dimension_index;
|
|
WHEN 'DLC_Story_LostHarvest_EcolabA' THEN return 'LostHarvest_EcolabA' || '_' || in_dimension_index;
|
|
WHEN 'DLC_Story_LostHarvest_EcolabB' THEN return 'LostHarvest_EcolabB' || '_' || in_dimension_index;
|
|
WHEN 'DLC_Story_LostHarvest_ForgottenLab' THEN return 'LostHarvest_ForgottenLab' || '_' || in_dimension_index;
|
|
WHEN 'Story_ArtOfKanly' THEN return 'ArtOfKanly' || '_' || in_dimension_index;
|
|
WHEN 'Story_HeighlinerDungeon' THEN return 'HeighlinerDungeon' || '_' || in_dimension_index;
|
|
WHEN 'CB_Dungeon_Hephaestus' THEN return 'WreckOfHephaestusDungeon' || '_' || in_dimension_index;
|
|
WHEN 'CB_Dungeon_OldCarthag' THEN return 'OldCarthagDungeon' || '_' || in_dimension_index;
|
|
WHEN 'CB_Story_BanditFortress01' THEN return 'SandfliesFortress' || '_' || in_dimension_index;
|
|
WHEN 'CB_Overland_S_05' THEN return 'ClosedOffTestingStationIsland' || '_' || in_dimension_index;
|
|
WHEN 'CB_Overland_S_06' THEN return 'GroundVehicleTimeTrialIsland' || '_' || in_dimension_index;
|
|
WHEN 'CB_Overland_S_04' THEN return 'ErythriteCaveIsland' || '_' || in_dimension_index;
|
|
WHEN 'CB_Overland_M_01' THEN return 'RadioactiveShipwreck' || '_' || in_dimension_index;
|
|
WHEN 'Story_Faction_Outpost_Hark' THEN return 'Story_Faction_Outpost_Hark' || '_' || in_dimension_index;
|
|
WHEN 'Story_Faction_Outpost_Atre' THEN return 'Story_Faction_Outpost_Atre' || '_' || in_dimension_index;
|
|
WHEN 'CB_Ecolab_Bronze_Green_089' THEN return 'RadiationDungeon' || '_' || in_dimension_index;
|
|
WHEN 'CB_Ecolab_Bronze_Green_152' THEN return 'ElectricityDungeon' || '_' || in_dimension_index;
|
|
WHEN 'CB_Ecolab_Bronze_Green_195' THEN return 'PoisonDungeon' || '_' || in_dimension_index;
|
|
WHEN 'CB_Ecolab_Bronze_Green_024' THEN return 'DarknessDungeon' || '_' || in_dimension_index;
|
|
WHEN 'CB_Ecolab_Bronze_Green_136' THEN return 'FireDungeon' || '_' || in_dimension_index;
|
|
WHEN 'CB_Overland_S_07' THEN return 'TheRuinsOfTsimpo' || '_' || in_dimension_index;
|
|
WHEN 'CB_Story_DestroyedZanovar' THEN return 'DestroyedZanovar' || '_' || in_dimension_index;
|
|
WHEN 'CB_Story_OrbitalMonitor' THEN return 'OrbitalMonitor' || '_' || in_dimension_index;
|
|
WHEN 'CB_Dungeon_TheFacility' THEN return 'FacilityDungeon' || '_' || in_dimension_index;
|
|
WHEN 'CB_Dungeon_ThePit' THEN return 'PitDungeon' || '_' || in_dimension_index;
|
|
WHEN 'Overmap' THEN
|
|
IF in_dimension_index = 0 THEN
|
|
return 'Overland';
|
|
END IF;
|
|
WHEN 'Survival_1' THEN
|
|
CASE in_dimension_index
|
|
WHEN 0 THEN return 'Abbir';
|
|
WHEN 1 THEN return 'Alraab';
|
|
WHEN 2 THEN return 'Barkan';
|
|
WHEN 3 THEN return 'Coanua';
|
|
WHEN 4 THEN return 'Fajr Kulon';
|
|
WHEN 5 THEN return 'Gara';
|
|
WHEN 6 THEN return 'Hajar';
|
|
WHEN 7 THEN return 'Jacurutu';
|
|
WHEN 8 THEN return 'Kathib';
|
|
WHEN 9 THEN return 'Legg';
|
|
WHEN 10 THEN return 'Makab';
|
|
WHEN 11 THEN return 'Nadir';
|
|
WHEN 12 THEN return 'Ramal';
|
|
WHEN 13 THEN return 'Rifana';
|
|
WHEN 14 THEN return 'Sandrat';
|
|
WHEN 15 THEN return 'Saajid';
|
|
WHEN 16 THEN return 'Tabr Sink';
|
|
WHEN 17 THEN return 'Tharwa';
|
|
WHEN 18 THEN return 'Umbu';
|
|
WHEN 19 THEN return 'Yaracuwan';
|
|
WHEN 20 THEN return 'al-Mut';
|
|
WHEN 21 THEN return 'Altuyur';
|
|
WHEN 22 THEN return 'Ammit';
|
|
WHEN 23 THEN return 'Ashia';
|
|
WHEN 24 THEN return 'Eaqrab';
|
|
WHEN 25 THEN return 'Hagga';
|
|
WHEN 26 THEN return 'Hua';
|
|
WHEN 27 THEN return 'Katal';
|
|
WHEN 28 THEN return 'Khafash';
|
|
WHEN 29 THEN return 'Matar';
|
|
WHEN 30 THEN return 'Rabie';
|
|
WHEN 31 THEN return 'Rajifiri';
|
|
WHEN 32 THEN return 'Remmel';
|
|
WHEN 33 THEN return 'Sahr';
|
|
WHEN 34 THEN return 'Saqer';
|
|
WHEN 35 THEN return 'Ta''lab';
|
|
WHEN 36 THEN return 'Tarl';
|
|
WHEN 37 THEN return 'Tasmin Sink';
|
|
WHEN 38 THEN return 'Thueban';
|
|
WHEN 39 THEN return 'Tuono';
|
|
ELSE
|
|
return 'Survival' || '_' || in_dimension_index;
|
|
END CASE;
|
|
ELSE
|
|
-- Do nothing
|
|
END CASE;
|
|
|
|
-- DeepDesert per-partition handling: if all 9 partitions exist, assign based on ordering
|
|
IF in_map = 'DeepDesert_1' THEN
|
|
SELECT count(*) INTO tmp_count FROM world_partition WHERE map = 'DeepDesert_1' AND dimension_index = in_dimension_index;
|
|
IF tmp_count = 9 AND in_partition_id IS NOT NULL THEN
|
|
RETURN (
|
|
WITH chess_notation AS (
|
|
SELECT label, ROW_NUMBER() OVER (ORDER BY null) AS row_num
|
|
FROM (select * from UNNEST(ARRAY['A1', 'B1', 'C1', 'A2', 'B2', 'C2', 'A3', 'B3', 'C3']) as label) as label_list
|
|
),
|
|
partitions AS (
|
|
SELECT partition_id, ROW_NUMBER() OVER (
|
|
order by
|
|
coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'max_x',
|
|
coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'max_y',
|
|
coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'min_x',
|
|
coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'min_y'
|
|
) AS row_num
|
|
FROM world_partition
|
|
where map = 'DeepDesert_1' AND dimension_index = in_dimension_index
|
|
)
|
|
SELECT 'DeepDesert_' || cn.label
|
|
FROM chess_notation cn
|
|
JOIN partitions p ON cn.row_num = p.row_num
|
|
WHERE p.partition_id = in_partition_id
|
|
LIMIT 1
|
|
);
|
|
END IF;
|
|
END IF;
|
|
|
|
IF in_partition_id IS NOT NULL THEN
|
|
SELECT coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'max_x', coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'max_y', coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'min_x', coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'min_y'
|
|
INTO tmp_box_max_x, tmp_box_max_y, tmp_box_min_x, tmp_box_min_y
|
|
FROM world_partition
|
|
WHERE partition_id = in_partition_id
|
|
LIMIT 1;
|
|
|
|
IF tmp_box_max_x IS NOT NULL AND tmp_box_max_x IN ('1.0','1') AND tmp_box_max_y IN ('1.0','1') AND tmp_box_min_x IN ('0.0','0') AND tmp_box_min_y IN ('0.0','0') THEN
|
|
RETURN upgrade_map_name(in_map) || '_' || in_dimension_index;
|
|
END IF;
|
|
ELSE
|
|
-- If we don't have a partition id, try to read any partition for that map/dimension
|
|
SELECT coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'max_x', coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'max_y', coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'min_x', coalesce(partition_definition->'box', partition_definition->'boxes'->0)->>'min_y'
|
|
INTO tmp_box_max_x, tmp_box_max_y, tmp_box_min_x, tmp_box_min_y
|
|
FROM world_partition
|
|
WHERE map = in_map AND dimension_index = in_dimension_index
|
|
LIMIT 1;
|
|
|
|
IF tmp_box_max_x IS NOT NULL AND tmp_box_max_x IN ('1.0','1') AND tmp_box_max_y IN ('1.0','1') AND tmp_box_min_x IN ('0.0','0') AND tmp_box_min_y IN ('0.0','0') THEN
|
|
RETURN upgrade_map_name(in_map) || '_' || in_dimension_index;
|
|
END IF;
|
|
END IF;
|
|
|
|
RETURN NULL;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- determine_partition_label_trigger() -> trigger
|
|
-- oid: 58236 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.determine_partition_label_trigger()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF NEW.label IS NULL THEN
|
|
UPDATE world_partition
|
|
SET label = determine_partition_label(NEW.map, NEW.dimension_index, NULL, false)
|
|
WHERE partition_id = NEW.partition_id;
|
|
END IF;
|
|
|
|
RETURN NULL; -- AFTER ROW trigger does not need to return a row
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- disband_guild(in_guild_id bigint) -> void
|
|
-- oid: 58237 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.disband_guild(in_guild_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_guild_name TEXT;
|
|
members_list BIGINT[];
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- check if guild exists
|
|
SELECT guild_name INTO out_guild_name FROM guilds WHERE guild_id = in_guild_id;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trying to disband non existing guild %.', in_guild_id;
|
|
END IF;
|
|
|
|
-- get members list
|
|
members_list := ARRAY(SELECT player_id FROM guild_members WHERE guild_id = in_guild_id);
|
|
|
|
-- delete
|
|
DELETE FROM guilds WHERE guild_id = in_guild_id;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('guild_disband#{"GuildId" : %s , "GuildName" : "%s", "PlayerIds" : %s}', in_guild_id, out_guild_name, to_json(members_list)::text));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- disband_party(in_party_id bigint) -> void
|
|
-- oid: 58238 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.disband_party(in_party_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
invite_ids BIGINT[];
|
|
sender_ids BIGINT[];
|
|
player_ids BIGINT[];
|
|
BEGIN
|
|
PERFORM parties_get_exclusive_operation_lock();
|
|
|
|
DELETE FROM party_members WHERE party_id = in_party_id;
|
|
DELETE FROM parties WHERE party_id = in_party_id;
|
|
DELETE FROM platform_parties_mapping WHERE dune_party_id = in_party_id;
|
|
|
|
WITH removed_invites AS (
|
|
DELETE FROM party_invites
|
|
WHERE party_id = in_party_id
|
|
RETURNING *
|
|
) SELECT array_agg(invite_id), array_agg(sender_player_id), array_agg(player_id) from removed_invites INTO invite_ids, sender_ids, player_ids;
|
|
|
|
PERFORM pg_notify('party_notify_channel', format('disband_party#{"PartyId" : %s, "InviteIds" : [%s] , "SenderIds" : [%s] , "PlayerIds" : [%s]}',
|
|
in_party_id, ARRAY_TO_STRING(invite_ids, ','), ARRAY_TO_STRING(sender_ids, ','), ARRAY_TO_STRING(player_ids, ',')));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- downgrade_map_name(in_map_name text) -> text
|
|
-- oid: 58239 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.downgrade_map_name(in_map_name text)
|
|
RETURNS text
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return
|
|
CASE in_map_name
|
|
WHEN 'HaggaBasin' THEN 'Survival_1'
|
|
WHEN 'HarkoVillage' THEN 'SH_HarkoVillage'
|
|
WHEN 'DeepDesert' THEN 'DeepDesert_1'
|
|
WHEN 'Overland' THEN 'Overmap'
|
|
WHEN 'Arrakeen' THEN 'SH_Arrakeen'
|
|
WHEN 'WreckOfHephaestus' THEN 'CB_Story_Hephaestus'
|
|
WHEN 'BeneathCarthag' THEN 'CB_Story_Ecolab_Carthag'
|
|
WHEN 'Station15' THEN 'CB_SurvivalChallenge_Station_15'
|
|
WHEN 'WaterFat' THEN 'CB_Story_WaterFatManor'
|
|
WHEN 'FallenLight' THEN 'SH_FallenLight'
|
|
WHEN 'ProcesVerbal' THEN 'Story_ProcesVerbal'
|
|
WHEN 'LostHarvest' THEN 'DLC_Story_LostHarvest'
|
|
WHEN 'LostHarvest_EcolabA' THEN 'DLC_Story_LostHarvest_EcolabA'
|
|
WHEN 'LostHarvest_EcolabB' THEN 'DLC_Story_LostHarvest_EcolabB'
|
|
WHEN 'LostHarvest_ForgottenLab' THEN 'DLC_Story_LostHarvest_ForgottenLab'
|
|
WHEN 'ArtOfKanly' THEN 'Story_ArtOfKanly'
|
|
WHEN 'HeighlinerDungeon' THEN 'Story_HeighlinerDungeon'
|
|
WHEN 'WreckOfHephaestusDungeon' THEN 'CB_Dungeon_Hephaestus'
|
|
WHEN 'OldCarthagDungeon' THEN 'CB_Dungeon_OldCarthag'
|
|
WHEN 'SandfliesFortress' THEN 'CB_Story_BanditFortress01'
|
|
WHEN 'ClosedOffTestingStationIsland' THEN 'CB_Overland_S_05'
|
|
WHEN 'GroundVehicleTimeTrialIsland' THEN 'CB_Overland_S_06'
|
|
WHEN 'ErythriteCaveIsland' THEN 'CB_Overland_S_04'
|
|
WHEN 'RadioactiveShipwreck' THEN 'CB_Overland_M_01'
|
|
WHEN 'TheRuinsOfTsimpo' THEN 'CB_Overland_S_07'
|
|
WHEN 'Story_Faction_Outpost_Hark' THEN 'Story_Faction_Outpost_Hark'
|
|
WHEN 'Story_Faction_Outpost_Atre' THEN 'Story_Faction_Outpost_Atre'
|
|
WHEN 'RadiationDungeon' THEN 'CB_Ecolab_Bronze_Green_089'
|
|
WHEN 'ElectricityDungeon' THEN 'CB_Ecolab_Bronze_Green_152'
|
|
WHEN 'PoisonDungeon' THEN 'CB_Ecolab_Bronze_Green_195'
|
|
WHEN 'DarknessDungeon' THEN 'CB_Ecolab_Bronze_Green_024'
|
|
WHEN 'FireDungeon' THEN 'CB_Ecolab_Bronze_Green_136'
|
|
WHEN 'DestroyedZanovar' THEN 'CB_Story_DestroyedZanovar'
|
|
WHEN 'OrbitalMonitor' THEN 'CB_Story_OrbitalMonitor'
|
|
WHEN 'FacilityDungeon' THEN 'CB_Dungeon_TheFacility'
|
|
WHEN 'PitDungeon' THEN 'CB_Dungeon_ThePit'
|
|
WHEN 'WindPass' THEN 'CB_Overland_S_08'
|
|
ELSE in_map_name
|
|
END;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- drain_item_tracking_data() -> TABLE(function_name dune.itemtrackingfunctiontype, item_id bigint, account_id bigint, inventory_id bigint, template_id text, event_time timestamp without time zone, position_index bigint)
|
|
-- oid: 58240 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.drain_item_tracking_data()
|
|
RETURNS TABLE(function_name dune.itemtrackingfunctiontype, item_id bigint, account_id bigint, inventory_id bigint, template_id text, event_time timestamp without time zone, position_index bigint)
|
|
LANGUAGE sql
|
|
AS $function$
|
|
DELETE FROM item_operations_staging_table
|
|
RETURNING
|
|
function_name,
|
|
item_id,
|
|
account_id,
|
|
inventory_id,
|
|
template_id,
|
|
event_time AT TIME ZONE 'UTC',
|
|
position_index;
|
|
$function$
|
|
|
|
|
|
-- dune_exchange_add_sell_order(in_exchange_id bigint, in_access_point_id bigint, in_owner_id bigint, in_max_orders_per_player integer, in_expiration_time bigint, in_item_id bigint, in_count bigint, in_category_mask integer, in_category_depth smallint, in_durability_cur real, in_durability_max real, in_item_price bigint, in_wear_normalized_item_price bigint, in_quality_level bigint, in_solari_cost bigint) -> dune.duneexchangeaddsellorderresult
|
|
-- oid: 58241 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_add_sell_order(in_exchange_id bigint, in_access_point_id bigint, in_owner_id bigint, in_max_orders_per_player integer, in_expiration_time bigint, in_item_id bigint, in_count bigint, in_category_mask integer, in_category_depth smallint, in_durability_cur real, in_durability_max real, in_item_price bigint, in_wear_normalized_item_price bigint, in_quality_level bigint, in_solari_cost bigint)
|
|
RETURNS dune.duneexchangeaddsellorderresult
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
exchange_inventory_id BIGINT;
|
|
user_id BIGINT;
|
|
new_item_id BIGINT;
|
|
item_template_id TEXT;
|
|
result DuneExchangeAddSellOrderResult;
|
|
fls_id TEXT;
|
|
BEGIN
|
|
result.order_id = 0;
|
|
SELECT INTO result.order_slots_used get_dune_exchange_used_order_slots(in_owner_id);
|
|
|
|
IF result.order_slots_used >= in_max_orders_per_player THEN
|
|
RETURN result;
|
|
END IF;
|
|
|
|
PERFORM * from dune_exchange_orders where item_id = in_item_id;
|
|
IF FOUND THEN
|
|
-- Debug logging
|
|
SELECT acc."user"
|
|
INTO fls_id
|
|
FROM accounts acc
|
|
JOIN player_state ps on ps.account_id = acc.id
|
|
WHERE ps.player_controller_id = in_owner_id
|
|
LIMIT 1;
|
|
PERFORM log_cheating(fls_id, 'exchange_order_dupe');
|
|
RAISE WARNING 'Trying to dupe exchange sell orders FLS: %', fls_id;
|
|
RETURN result;
|
|
END IF;
|
|
|
|
SELECT INTO user_id dune_exchange_get_user_id(in_owner_id);
|
|
SELECT INTO exchange_inventory_id get_exchange_inventory_id(in_exchange_id);
|
|
|
|
IF exchange_inventory_id IS NULL THEN
|
|
RETURN result;
|
|
END IF;
|
|
|
|
UPDATE dune_exchange_users SET solari_balance = solari_balance - in_solari_cost WHERE id = user_id AND solari_balance >= in_solari_cost;
|
|
|
|
IF NOT FOUND THEN
|
|
RETURN result;
|
|
END IF;
|
|
|
|
SELECT INTO STRICT item_template_id template_id FROM items WHERE id = in_item_id FOR UPDATE;
|
|
INSERT INTO dune_exchange_orders(exchange_id, access_point_id, owner_id, expiration_time, template_id, durability_cur, durability_max, category_mask, category_depth, item_price, quality_level)
|
|
VALUES(in_exchange_id, in_access_point_id, in_owner_id, in_expiration_time, item_template_id, in_durability_cur, in_durability_max, in_category_mask, in_category_depth, in_item_price, in_quality_level)
|
|
RETURNING id INTO result.order_id;
|
|
|
|
INSERT INTO dune_exchange_sell_orders(order_id, initial_stack_size, wear_normalized_price) VALUES(result.order_id, in_count, in_wear_normalized_item_price);
|
|
SELECT INTO new_item_id move_inventory_item(in_item_id, exchange_inventory_id, result.order_id, in_count);
|
|
|
|
IF new_item_id IS NULL THEN
|
|
RAISE EXCEPTION 'Failed to move inventory item %', in_item_id;
|
|
END IF;
|
|
|
|
UPDATE dune_exchange_orders SET item_id = new_item_id WHERE id = result.order_id;
|
|
|
|
result.order_slots_used = result.order_slots_used + 1;
|
|
|
|
RETURN result;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_cancel_order(in_order_id bigint, in_purge_time bigint, in_completion_type integer) -> void
|
|
-- oid: 58242 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_cancel_order(in_order_id bigint, in_purge_time bigint, in_completion_type integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
DELETE FROM dune_exchange_sell_orders WHERE order_id = in_order_id;
|
|
IF NOT FOUND THEN
|
|
RETURN;
|
|
END IF;
|
|
|
|
WITH item_stack_size AS
|
|
(SELECT item.stack_size
|
|
FROM dune_exchange_orders ord
|
|
JOIN items item ON ord.item_id = item.id
|
|
WHERE ord.id = in_order_id)
|
|
INSERT INTO dune_exchange_fulfilled_orders(order_id, completion_type, stack_size, original_order_id) VALUES(in_order_id, in_completion_type, (SELECT * FROM item_stack_size), in_order_id);
|
|
|
|
UPDATE dune_exchange_orders SET expiration_time = in_purge_time, revision = revision + 1 WHERE id = in_order_id;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_expire_orders(in_exchange_id bigint, in_current_time bigint, in_purge_time bigint, in_expired_completion_type integer) -> SETOF dune.exchangeexpiredorder
|
|
-- oid: 58243 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_expire_orders(in_exchange_id bigint, in_current_time bigint, in_purge_time bigint, in_expired_completion_type integer)
|
|
RETURNS SETOF dune.exchangeexpiredorder
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
cur_order RECORD;
|
|
order_is_npc_order BOOLEAN;
|
|
BEGIN
|
|
FOR cur_order IN
|
|
SELECT
|
|
ord.id AS order_id,
|
|
ord.owner_id AS owner_id,
|
|
ord.is_npc_order AS is_npc_order,
|
|
item.stack_size AS stack_size,
|
|
ord.item_price AS item_price,
|
|
ord.quality_level AS quality_level
|
|
FROM dune_exchange_orders ord
|
|
JOIN dune_exchange_sell_orders sord ON (ord.id = sord.order_id)
|
|
JOIN items item ON (ord.item_id = item.id)
|
|
WHERE ord.exchange_id = in_exchange_id AND ord.expiration_time IS NOT NULL AND in_current_time >= ord.expiration_time
|
|
FOR UPDATE
|
|
LOOP
|
|
IF NOT cur_order.is_npc_order THEN
|
|
-- Make an item_storage record for the order item.
|
|
DELETE FROM dune_exchange_sell_orders WHERE order_id = cur_order.order_id;
|
|
INSERT INTO dune_exchange_fulfilled_orders(order_id, completion_type, stack_size, original_order_id) VALUES(cur_order.order_id, in_expired_completion_type, cur_order.stack_size, cur_order.order_id);
|
|
UPDATE dune_exchange_orders SET revision = revision + 1, expiration_time = in_purge_time WHERE id = cur_order.order_id;
|
|
|
|
RETURN NEXT (
|
|
cur_order.order_id,
|
|
cur_order.owner_id,
|
|
in_expired_completion_type,
|
|
cur_order.stack_size,
|
|
cur_order.item_price,
|
|
cur_order.order_id,
|
|
cur_order.quality_level);
|
|
ELSE
|
|
-- Delete the order. Will cascade into the items table.
|
|
DELETE FROM dune_exchange_orders WHERE id = order_id;
|
|
END IF;
|
|
|
|
END LOOP;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_fulfill_sell_order(in_exchange_id bigint, in_max_orders_per_player integer, in_purchased_completion_type integer, in_sold_completion_type integer, in_instigator_id bigint, in_order_id bigint, in_order_revision bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint, in_solaris_fee bigint, in_purge_time bigint) -> dune.duneexchangefulfillsellorderresult
|
|
-- oid: 58244 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_fulfill_sell_order(in_exchange_id bigint, in_max_orders_per_player integer, in_purchased_completion_type integer, in_sold_completion_type integer, in_instigator_id bigint, in_order_id bigint, in_order_revision bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint, in_solaris_fee bigint, in_purge_time bigint)
|
|
RETURNS dune.duneexchangefulfillsellorderresult
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
exchange_inventory_id BIGINT;
|
|
order_access_point_id BIGINT;
|
|
seller_actor_id BIGINT;
|
|
seller_user_id BIGINT;
|
|
buyer_user_id BIGINT;
|
|
user_solari_balance BIGINT;
|
|
per_item_price BIGINT;
|
|
total_cost BIGINT;
|
|
order_revision BIGINT;
|
|
order_item_id BIGINT;
|
|
order_is_npc_order BOOLEAN;
|
|
order_category_mask INT;
|
|
order_category_depth SMALLINT;
|
|
item_template_id TEXT;
|
|
item_durability_cur REAL;
|
|
item_durability_max REAL;
|
|
storage_order_id BIGINT;
|
|
log_order_id BIGINT;
|
|
result DuneExchangeFulfillSellOrderResult;
|
|
|
|
BEGIN
|
|
result.item_id = 0;
|
|
SELECT INTO result.order_slots_used get_dune_exchange_used_order_slots(in_instigator_id);
|
|
|
|
IF result.order_slots_used >= in_max_orders_per_player THEN
|
|
RETURN result;
|
|
END IF;
|
|
|
|
SELECT INTO exchange_inventory_id get_exchange_inventory_id(in_exchange_id);
|
|
SELECT INTO buyer_user_id dune_exchange_get_user_id(in_instigator_id);
|
|
|
|
BEGIN
|
|
SELECT INTO STRICT user_solari_balance solari_balance FROM dune_exchange_users WHERE id = buyer_user_id FOR UPDATE;
|
|
SELECT INTO STRICT
|
|
order_revision,
|
|
order_access_point_id,
|
|
order_item_id,
|
|
item_template_id,
|
|
item_durability_cur,
|
|
item_durability_max,
|
|
seller_actor_id,
|
|
order_category_mask,
|
|
order_category_depth,
|
|
order_is_npc_order,
|
|
per_item_price
|
|
|
|
ord.revision,
|
|
ord.access_point_id,
|
|
ord.item_id,
|
|
ord.template_id,
|
|
ord.durability_cur,
|
|
ord.durability_max,
|
|
ord.owner_id,
|
|
ord.category_mask,
|
|
ord.category_depth,
|
|
ord.is_npc_order,
|
|
ord.item_price
|
|
FROM
|
|
dune_exchange_orders ord
|
|
JOIN dune_exchange_sell_orders sord ON (ord.id = sord.order_id)
|
|
WHERE
|
|
id = in_order_id AND revision = in_order_revision
|
|
FOR UPDATE;
|
|
EXCEPTION
|
|
WHEN NO_DATA_FOUND THEN RETURN result;
|
|
END;
|
|
|
|
IF order_revision != in_order_revision THEN
|
|
RETURN result;
|
|
END IF;
|
|
|
|
IF NOT order_is_npc_order THEN
|
|
SELECT INTO seller_user_id dune_exchange_get_user_id(seller_actor_id);
|
|
END IF;
|
|
total_cost = per_item_price * in_count + in_solaris_fee;
|
|
|
|
IF total_cost > user_solari_balance THEN
|
|
RETURN result;
|
|
END IF;
|
|
|
|
IF in_dst_inventory_id IS NULL THEN
|
|
-- Item is to be transferred to exchange storage rather than an external inventory. Make a record for it.
|
|
INSERT INTO dune_exchange_orders(exchange_id, access_point_id, owner_id, template_id, expiration_time, durability_cur, durability_max, item_price, category_mask, category_depth)
|
|
VALUES(in_exchange_id, order_access_point_id, in_instigator_id, item_template_id, in_purge_time, item_durability_cur, item_durability_max, per_item_price, order_category_mask, order_category_depth)
|
|
RETURNING id INTO storage_order_id;
|
|
|
|
INSERT INTO dune_exchange_fulfilled_orders(order_id, completion_type, stack_size, original_order_id)
|
|
VALUES(storage_order_id, in_purchased_completion_type, in_count, in_order_id);
|
|
|
|
in_dst_inventory_id = exchange_inventory_id;
|
|
in_dst_index = storage_order_id;
|
|
END IF;
|
|
|
|
UPDATE dune_exchange_orders SET item_id = NULL WHERE id = in_order_id;
|
|
|
|
SELECT INTO result.item_id move_inventory_item(order_item_id, in_dst_inventory_id, in_dst_index, in_count);
|
|
|
|
IF result.item_id IS NULL THEN
|
|
IF storage_order_id IS NOT NULL THEN
|
|
DELETE FROM dune_exchange_orders WHERE id = storage_order_id;
|
|
END IF;
|
|
RETURN result;
|
|
END IF;
|
|
|
|
-- Create an entry for the fulfilled orders log.
|
|
SELECT INTO log_order_id order_id FROM dune_exchange_fulfilled_orders where source_order_id = in_order_id FOR SHARE;
|
|
|
|
IF log_order_id IS NOT NULL THEN
|
|
UPDATE dune_exchange_orders SET expiration_time = in_purge_time, revision = revision + 1 WHERE id = log_order_id;
|
|
UPDATE dune_exchange_fulfilled_orders SET stack_size = stack_size + in_count WHERE order_id = log_order_id;
|
|
ELSE
|
|
INSERT INTO dune_exchange_orders(exchange_id, access_point_id, owner_id, template_id, expiration_time, durability_cur, durability_max, item_price, category_mask, category_depth)
|
|
VALUES(in_exchange_id, order_access_point_id, seller_actor_id, item_template_id, in_purge_time, item_durability_cur, item_durability_max, per_item_price, order_category_mask, order_category_depth) RETURNING id INTO log_order_id;
|
|
|
|
INSERT INTO dune_exchange_fulfilled_orders(order_id, source_order_id, completion_type, stack_size, original_order_id)
|
|
VALUES(log_order_id, in_order_id, in_sold_completion_type, in_count, in_order_id);
|
|
END IF;
|
|
|
|
UPDATE dune_exchange_users SET solari_balance = solari_balance - total_cost WHERE id = buyer_user_id;
|
|
-- If the new ID is equal to the old ID the item/stack was moved rather than split and the order is now empty
|
|
IF result.item_id = order_item_id THEN
|
|
DELETE FROM dune_exchange_orders WHERE id = in_order_id;
|
|
ELSE
|
|
UPDATE dune_exchange_orders SET item_id = order_item_id, revision = revision + 1 WHERE id = in_order_id; -- Item was split. Restore reference to remaining items.
|
|
END IF;
|
|
-- If the item was transferred to exchange storage rather than an external inventory, update the record with the item ID.
|
|
IF storage_order_id IS NOT NULL THEN
|
|
UPDATE dune_exchange_orders SET item_id = result.item_id WHERE id = storage_order_id;
|
|
END IF;
|
|
|
|
result.order_slots_used = result.order_slots_used + 1;
|
|
|
|
RETURN result;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_get_item_price_stats(in_template_ids text[]) -> TABLE(template_id text, minimum bigint, average bigint)
|
|
-- oid: 58246 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_get_item_price_stats(in_template_ids text[])
|
|
RETURNS TABLE(template_id text, minimum bigint, average bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
average_price REAL;
|
|
minimum_price REAL;
|
|
BEGIN
|
|
RETURN QUERY SELECT ord.template_id, MIN(sord.wear_normalized_price), CAST(SUM(sord.wear_normalized_price * item.stack_size) / SUM(item.stack_size) AS BIGINT)
|
|
FROM dune_exchange_orders ord
|
|
JOIN items item ON item.id = ord.item_id
|
|
JOIN dune_exchange_sell_orders sord ON sord.order_id = ord.id
|
|
WHERE ord.template_id = ANY(in_template_ids) GROUP BY ord.template_id;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_get_user_id(in_owner_id bigint) -> bigint
|
|
-- oid: 58247 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_get_user_id(in_owner_id bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
new_user_id BIGINT;
|
|
user_id BIGINT;
|
|
BEGIN
|
|
INSERT INTO dune_exchange_users(owner_id) VALUES(in_owner_id) ON CONFLICT DO NOTHING RETURNING id INTO new_user_id;
|
|
SELECT INTO user_id COALESCE(new_user_id, id) FROM dune_exchange_users WHERE owner_id = in_owner_id;
|
|
|
|
return user_id;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_modify_user_solari_balance(in_controller_id bigint, in_solari_delta bigint) -> void
|
|
-- oid: 58248 kind: FUNCTION category: currency
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_modify_user_solari_balance(in_controller_id bigint, in_solari_delta bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
user_id BIGINT;
|
|
current_balance BIGINT;
|
|
new_balance BIGINT;
|
|
delta_balance BIGINT;
|
|
fls_id TEXT;
|
|
function_oid oid;
|
|
BEGIN
|
|
SELECT INTO user_id dune_exchange_get_user_id(in_controller_id);
|
|
SELECT INTO current_balance balance from player_virtual_currency_balances WHERE currency_id = get_solaris_id() AND player_controller_id = in_controller_id;
|
|
|
|
IF current_balance < 0 THEN
|
|
SELECT acc."user"
|
|
INTO fls_id
|
|
FROM accounts acc
|
|
JOIN player_state ps on ps.account_id = acc.id
|
|
WHERE ps.player_controller_id = in_controller_id
|
|
LIMIT 1;
|
|
|
|
PERFORM log_cheating(COALESCE(fls_id, in_controller_id::text), 'exchange_negative_solaris');
|
|
UPDATE player_virtual_currency_balances SET balance = 0 WHERE currency_id = get_solaris_id() AND player_controller_id = in_controller_id;
|
|
current_balance = 0;
|
|
END IF;
|
|
|
|
delta_balance = in_solari_delta;
|
|
IF current_balance < in_solari_delta THEN
|
|
delta_balance = current_balance;
|
|
END IF;
|
|
|
|
UPDATE dune_exchange_users SET solari_balance = solari_balance + delta_balance WHERE id = user_id;
|
|
|
|
UPDATE player_virtual_currency_balances SET balance = balance - delta_balance WHERE currency_id = get_solaris_id() AND player_controller_id = in_controller_id RETURNING player_virtual_currency_balances.balance INTO new_balance;
|
|
|
|
GET DIAGNOSTICS function_oid = PG_ROUTINE_OID;
|
|
PERFORM log_event_solaris(function_oid, 'update_solaris', in_controller_id, new_balance, delta_balance);
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_purge_completed_orders(in_exchange_id bigint, in_current_time bigint) -> SETOF dune.exchangeexpiredorder
|
|
-- oid: 58249 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_purge_completed_orders(in_exchange_id bigint, in_current_time bigint)
|
|
RETURNS SETOF dune.exchangeexpiredorder
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
cur_order RECORD;
|
|
order_is_npc_order BOOLEAN;
|
|
BEGIN
|
|
FOR cur_order IN
|
|
SELECT
|
|
ord.id AS order_id,
|
|
ord.owner_id AS owner_id,
|
|
ord.is_npc_order AS is_npc_order,
|
|
sord.stack_size AS stack_size,
|
|
ord.item_price AS item_price,
|
|
sord.completion_type AS completion_type,
|
|
sord.original_order_id AS original_order_id,
|
|
ord.quality_level AS quality_level
|
|
FROM dune_exchange_orders ord
|
|
JOIN dune_exchange_fulfilled_orders sord ON (ord.id = sord.order_id)
|
|
WHERE ord.exchange_id = in_exchange_id AND ord.expiration_time IS NOT NULL AND in_current_time >= ord.expiration_time
|
|
FOR UPDATE
|
|
LOOP
|
|
DELETE FROM dune_exchange_orders WHERE id = cur_order.order_id;
|
|
RETURN NEXT (
|
|
cur_order.order_id,
|
|
cur_order.owner_id,
|
|
cur_order.completion_type,
|
|
cur_order.stack_size,
|
|
cur_order.item_price,
|
|
cur_order.original_order_id,
|
|
cur_order.quality_level);
|
|
END LOOP;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_query_storage_item(in_order_id bigint) -> TABLE(completion_type integer, id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, item_id bigint, template_id text, stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
-- oid: 58250 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_query_storage_item(in_order_id bigint)
|
|
RETURNS TABLE(completion_type integer, id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, item_id bigint, template_id text, stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT sord.completion_type, ord.id, ord.revision, ord.expiration_time, ord.access_point_id, ap.name, ord.owner_id, ord.item_id, ord.template_id, sord.stack_size, ord.item_price, ord.quality_level, ord.durability_cur, ord.durability_max, item.stats
|
|
FROM dune_exchange_orders ord
|
|
JOIN dune_exchange_fulfilled_orders sord ON (ord.id = sord.order_id)
|
|
JOIN dune_exchange_accesspoints ap ON (ord.access_point_id = ap.id)
|
|
LEFT JOIN items item ON ord.item_id = item.id
|
|
WHERE ord.id = in_order_id;
|
|
END; $function$
|
|
|
|
|
|
-- dune_exchange_query_storage_items(in_exchange_id bigint, in_owner_id bigint) -> TABLE(completion_type integer, id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, item_id bigint, template_id text, stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
-- oid: 58251 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_query_storage_items(in_exchange_id bigint, in_owner_id bigint)
|
|
RETURNS TABLE(completion_type integer, id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, item_id bigint, template_id text, stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT sord.completion_type, ord.id, ord.revision, ord.expiration_time, ord.access_point_id, ap.name, ord.owner_id, ord.item_id, ord.template_id, sord.stack_size, ord.item_price, ord.quality_level, ord.durability_cur, ord.durability_max, item.stats
|
|
FROM dune_exchange_orders ord
|
|
JOIN dune_exchange_fulfilled_orders sord ON (ord.id = sord.order_id)
|
|
JOIN dune_exchange_accesspoints ap ON (ord.access_point_id = ap.id)
|
|
LEFT JOIN items item ON ord.item_id = item.id
|
|
WHERE ord.exchange_id = in_exchange_id AND ord.owner_id = in_owner_id;
|
|
END; $function$
|
|
|
|
|
|
-- dune_exchange_relist_order(in_order_id bigint, in_expiration_time bigint, in_item_price bigint, in_wear_normalized_item_price bigint, in_solari_cost bigint) -> bigint
|
|
-- oid: 58252 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_relist_order(in_order_id bigint, in_expiration_time bigint, in_item_price bigint, in_wear_normalized_item_price bigint, in_solari_cost bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
user_id BIGINT;
|
|
initial_stack_size BIGINT;
|
|
BEGIN
|
|
WITH order_owner_id AS
|
|
(SELECT ord.owner_id
|
|
FROM dune_exchange_orders ord
|
|
JOIN dune_exchange_fulfilled_orders ford ON (ord.id = ford.order_id)
|
|
WHERE id = in_order_id AND item_id IS NOT NULL)
|
|
SELECT INTO user_id dune_exchange_get_user_id((SELECT * FROM order_owner_id));
|
|
|
|
UPDATE dune_exchange_users SET solari_balance = solari_balance - in_solari_cost WHERE id = user_id AND solari_balance >= in_solari_cost;
|
|
|
|
IF NOT FOUND THEN
|
|
RETURN 0;
|
|
END IF;
|
|
|
|
DELETE FROM dune_exchange_fulfilled_orders WHERE order_id = in_order_id;
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Order % is not a fulfilled order', in_order_id;
|
|
END IF;
|
|
|
|
WITH item_stack_size AS
|
|
(SELECT item.stack_size
|
|
FROM dune_exchange_orders ord
|
|
JOIN items item ON ord.item_id = item.id
|
|
WHERE ord.id = in_order_id)
|
|
INSERT INTO dune_exchange_sell_orders(order_id, initial_stack_size, wear_normalized_price) VALUES(in_order_id, (SELECT * FROM item_stack_size), in_wear_normalized_item_price) RETURNING dune_exchange_sell_orders.initial_stack_size INTO initial_stack_size;
|
|
|
|
UPDATE dune_exchange_orders SET item_price = in_item_price, expiration_time = in_expiration_time WHERE id = in_order_id;
|
|
|
|
RETURN initial_stack_size;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_retrieve_solari_balance(in_owner_id bigint) -> bigint
|
|
-- oid: 58253 kind: FUNCTION category: currency
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_retrieve_solari_balance(in_owner_id bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
current_balance BIGINT;
|
|
fls_id TEXT;
|
|
BEGIN
|
|
SELECT INTO current_balance solari_balance from dune_exchange_users WHERE owner_id = in_owner_id LIMIT 1;
|
|
|
|
IF current_balance < 0 THEN
|
|
SELECT acc."user"
|
|
INTO fls_id
|
|
FROM accounts acc
|
|
JOIN player_state ps on ps.account_id = acc.id
|
|
WHERE ps.player_controller_id = in_owner_id
|
|
LIMIT 1;
|
|
|
|
PERFORM log_cheating(COALESCE(fls_id, in_owner_id::text), 'exchange_negative_solaris');
|
|
|
|
UPDATE dune_exchange_users SET solari_balance = 0 WHERE owner_id = in_owner_id;
|
|
END IF;
|
|
RETURN (SELECT solari_balance FROM dune_exchange_users WHERE owner_id = in_owner_id LIMIT 1);
|
|
END; $function$
|
|
|
|
|
|
-- dune_exchange_retrieve_solaris_from_item(in_controller_id bigint, in_order_id bigint) -> dune.duneexchangeretrievesolarisfromitemresult
|
|
-- oid: 58254 kind: FUNCTION category: currency
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_retrieve_solaris_from_item(in_controller_id bigint, in_order_id bigint)
|
|
RETURNS dune.duneexchangeretrievesolarisfromitemresult
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result DuneExchangeRetrieveSolarisFromItemResult;
|
|
new_balance BIGINT;
|
|
function_oid oid;
|
|
BEGIN
|
|
WITH
|
|
delete_orders_prices AS (
|
|
DELETE FROM dune_exchange_orders
|
|
USING dune_exchange_fulfilled_orders
|
|
WHERE (dune_exchange_orders.id = dune_exchange_fulfilled_orders.order_id)
|
|
AND id = in_order_id AND (item_id IS NULL OR item_id = 0)
|
|
RETURNING item_price * dune_exchange_fulfilled_orders.stack_size AS total_price
|
|
),
|
|
total_price AS (
|
|
SELECT SUM(total_price) AS delta FROM delete_orders_prices
|
|
)
|
|
UPDATE player_virtual_currency_balances
|
|
SET balance = balance + total_price.delta
|
|
FROM total_price
|
|
WHERE currency_id = get_solaris_id() AND player_controller_id = in_controller_id
|
|
RETURNING
|
|
player_virtual_currency_balances.balance,
|
|
total_price.delta,
|
|
(SELECT original_order_id FROM dune_exchange_fulfilled_orders WHERE order_id = in_order_id)
|
|
INTO
|
|
new_balance,
|
|
result.total_item_value,
|
|
result.original_order_id;
|
|
|
|
GET DIAGNOSTICS function_oid = PG_ROUTINE_OID;
|
|
PERFORM log_event_solaris(function_oid, 'update_solaris', in_controller_id, new_balance, result.total_item_value);
|
|
|
|
RETURN result;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_retrieve_storage_item(in_exchange_id bigint, in_order_id bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint) -> dune.duneexchangeretrievestorageorderresult
|
|
-- oid: 58255 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_retrieve_storage_item(in_exchange_id bigint, in_order_id bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint)
|
|
RETURNS dune.duneexchangeretrievestorageorderresult
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
exchange_inventory_id BIGINT;
|
|
order_owner_id BIGINT;
|
|
order_item_id BIGINT;
|
|
result DuneExchangeRetrieveStorageOrderResult;
|
|
BEGIN
|
|
SELECT INTO exchange_inventory_id get_exchange_inventory_id(in_exchange_id);
|
|
|
|
IF exchange_inventory_id IS NULL THEN
|
|
RETURN NULL;
|
|
END IF;
|
|
|
|
SELECT INTO STRICT order_owner_id, order_item_id owner_id, item_id
|
|
FROM dune_exchange_orders
|
|
JOIN dune_exchange_fulfilled_orders ON (dune_exchange_orders.id = dune_exchange_fulfilled_orders.order_id)
|
|
WHERE id = in_order_id
|
|
FOR UPDATE;
|
|
|
|
UPDATE dune_exchange_orders SET item_id = NULL WHERE id = in_order_id;
|
|
|
|
SELECT INTO result.item_id move_inventory_item(order_item_id, in_dst_inventory_id, in_dst_index, in_count);
|
|
|
|
IF result.item_id IS NULL THEN
|
|
RAISE EXCEPTION 'Failed to move inventory item % on order %', in_item_id, in_order_id;
|
|
END IF;
|
|
|
|
SELECT INTO result.original_order_id original_order_id FROM dune_exchange_fulfilled_orders WHERE order_id = in_order_id;
|
|
|
|
-- If the new ID is equal to the old ID the item/stack was moved rather than split and the order is now empty
|
|
IF result.item_id = order_item_id THEN
|
|
DELETE FROM dune_exchange_orders WHERE id = in_order_id;
|
|
ELSE
|
|
UPDATE dune_exchange_orders SET item_id = order_item_id WHERE id = in_order_id; -- Item was split. Restore reference to remaining items.
|
|
UPDATE dune_exchange_fulfilled_orders SET stack_size = stack_size - in_count WHERE order_id = in_order_id;
|
|
END IF;
|
|
|
|
SELECT INTO result.order_slots_used get_dune_exchange_used_order_slots(order_owner_id);
|
|
|
|
RETURN result;
|
|
END $function$
|
|
|
|
|
|
-- dune_exchange_update_recurring_sell_order(in_exchange_id bigint, in_expiration_time bigint, in_access_point_id bigint, in_owner_id bigint, in_item_id bigint, in_increment bigint, in_max_count bigint, in_category_mask integer, in_category_depth smallint, in_durability_cur real, in_durability_max real, in_item_price bigint, in_wear_normalized_item_price bigint, in_quality_level bigint) -> bigint
|
|
-- oid: 58256 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_exchange_update_recurring_sell_order(in_exchange_id bigint, in_expiration_time bigint, in_access_point_id bigint, in_owner_id bigint, in_item_id bigint, in_increment bigint, in_max_count bigint, in_category_mask integer, in_category_depth smallint, in_durability_cur real, in_durability_max real, in_item_price bigint, in_wear_normalized_item_price bigint, in_quality_level bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
exchange_inventory_id BIGINT;
|
|
new_item_id BIGINT;
|
|
item_stack_size BIGINT;
|
|
new_order_id BIGINT;
|
|
item_template_id TEXT;
|
|
old_count BIGINT;
|
|
new_count BIGINT;
|
|
delta_count BIGINT;
|
|
BEGIN
|
|
LOCK TABLE dune_exchange_orders, items IN ROW EXCLUSIVE MODE;
|
|
|
|
SELECT INTO exchange_inventory_id get_exchange_inventory_id(in_exchange_id);
|
|
|
|
IF exchange_inventory_id IS NULL THEN
|
|
RETURN 0;
|
|
END IF;
|
|
|
|
SELECT INTO STRICT item_template_id template_id FROM items WHERE id = in_item_id FOR SHARE;
|
|
|
|
SELECT INTO new_order_id, new_item_id ord.id, ord.item_id
|
|
FROM dune_exchange_orders ord
|
|
JOIN dune_exchange_sell_orders sord ON (ord.id = sord.order_id)
|
|
WHERE ord.is_npc_order = TRUE AND ord.exchange_id = in_exchange_id AND ord.access_point_id = in_access_point_id AND ord.template_id = item_template_id AND ord.item_price = in_item_price AND ord.quality_level = in_quality_level
|
|
FOR SHARE;
|
|
|
|
IF new_order_id IS NULL THEN
|
|
INSERT INTO dune_exchange_orders(exchange_id, access_point_id, owner_id, is_npc_order, expiration_time, template_id, durability_cur, durability_max, category_mask, category_depth, item_price, quality_level)
|
|
VALUES(in_exchange_id, in_access_point_id, in_owner_id, TRUE, in_expiration_time, item_template_id, in_durability_cur, in_durability_max, in_category_mask, in_category_depth, in_item_price, in_quality_level)
|
|
RETURNING id INTO new_order_id;
|
|
|
|
INSERT INTO dune_exchange_sell_orders(order_id, initial_stack_size, wear_normalized_price) VALUES(new_order_id, new_count, in_wear_normalized_item_price);
|
|
SELECT INTO new_item_id move_inventory_item(in_item_id, exchange_inventory_id, new_order_id, in_increment);
|
|
|
|
IF new_item_id IS NULL THEN
|
|
DELETE FROM dune_exchange_orders WHERE id = new_order_id;
|
|
RETURN 0;
|
|
END IF;
|
|
|
|
UPDATE dune_exchange_orders SET item_id = new_item_id WHERE id = new_order_id;
|
|
|
|
RETURN in_increment;
|
|
ELSE
|
|
UPDATE dune_exchange_orders SET expiration_time = in_expiration_time WHERE id=new_order_id;
|
|
SELECT INTO STRICT old_count stack_size FROM items WHERE id = new_item_id FOR SHARE;
|
|
new_count = old_count + in_increment;
|
|
IF new_count > in_max_count THEN new_count = in_max_count; END IF;
|
|
IF new_count != old_count THEN
|
|
delta_count = new_count - old_count;
|
|
SELECT INTO new_item_id merge_or_move_inventory_item(in_item_id, exchange_inventory_id, new_order_id, delta_count);
|
|
RETURN delta_count;
|
|
END IF;
|
|
|
|
RETURN 0;
|
|
END IF;
|
|
END $function$
|
|
|
|
|
|
-- dune_get_account_id_by_user(in_user text) -> bigint
|
|
-- oid: 58257 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.dune_get_account_id_by_user(in_user text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
account_id BIGINT;
|
|
BEGIN
|
|
SELECT INTO account_id id FROM accounts WHERE "user"=in_user;
|
|
RETURN account_id;
|
|
END $function$
|
|
|
|
|
|
-- edit_guild_description(in_guild_id bigint, in_guild_desc text) -> void
|
|
-- oid: 58258 kind: FUNCTION category: currency
|
|
|
|
CREATE OR REPLACE FUNCTION dune.edit_guild_description(in_guild_id bigint, in_guild_desc text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_guild_description TEXT;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- check if guild exists
|
|
SELECT guild_description INTO out_guild_description FROM guilds WHERE guild_id = in_guild_id;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trying to add invite to non existing guild %.', in_guild_id;
|
|
END IF;
|
|
|
|
UPDATE guilds SET guild_description = in_guild_desc WHERE guilds.guild_id = in_guild_id;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('edit_guild_description#{"GuildId" : %s}', in_guild_id));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- encrypt_user_data(in_data text) -> bytea
|
|
-- oid: 58259 kind: FUNCTION category: encryption
|
|
|
|
CREATE OR REPLACE FUNCTION dune.encrypt_user_data(in_data text)
|
|
RETURNS bytea
|
|
LANGUAGE sql
|
|
IMMUTABLE
|
|
AS $function$select convert_to(in_data, 'utf8')$function$
|
|
|
|
|
|
-- fetch_resourcefield_state(in_map text, in_dimension_index integer, in_field_kind_id smallint) -> TABLE(field_id bigint, spawn_time double precision, value_remaining bigint)
|
|
-- oid: 58260 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.fetch_resourcefield_state(in_map text, in_dimension_index integer, in_field_kind_id smallint)
|
|
RETURNS TABLE(field_id bigint, spawn_time double precision, value_remaining bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT resourcefield_state.field_id, resourcefield_state.spawn_time, resourcefield_state.value_remaining
|
|
FROM resourcefield_state
|
|
WHERE map = in_map AND dimension_index = in_dimension_index AND field_kind_id = in_field_kind_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- fetch_server_spice_field_manifest(in_server_id text) -> TABLE(spicefield_type_id integer, inactive_fields_of_type integer, requested_spawned_of_type integer)
|
|
-- oid: 58261 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.fetch_server_spice_field_manifest(in_server_id text)
|
|
RETURNS TABLE(spicefield_type_id integer, inactive_fields_of_type integer, requested_spawned_of_type integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT t.spicefield_type_id, t.inactive_fields_of_type, t.requested_spawned_of_type
|
|
FROM spicefield_server_availability as t
|
|
WHERE t.server_id = in_server_id;
|
|
END; $function$
|
|
|
|
|
|
-- fetch_spicefie_id_types_with_global_info(in_map_name text, in_dimension_index integer) -> TABLE(spicefield_type_id integer, max_globally_active integer, max_globally_primed integer, current_globally_active integer, current_globally_primed integer, is_spawning_active boolean, field_type text)
|
|
-- oid: 58262 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.fetch_spicefie_id_types_with_global_info(in_map_name text, in_dimension_index integer)
|
|
RETURNS TABLE(spicefield_type_id integer, max_globally_active integer, max_globally_primed integer, current_globally_active integer, current_globally_primed integer, is_spawning_active boolean, field_type text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT t.spicefield_type_id, t.max_globally_active, t.max_globally_primed, t.current_globally_active, t.current_globally_primed, t.is_spawning_active, t.field_type
|
|
FROM spicefield_types as t
|
|
WHERE t.map_name = in_map_name AND t.dimension_index = in_dimension_index;
|
|
END; $function$
|
|
|
|
|
|
-- find_actor_by_id(in_id bigint) -> dune.actorspawninfo
|
|
-- oid: 58263 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.find_actor_by_id(in_id bigint)
|
|
RETURNS dune.actorspawninfo
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return (select (id, class, transform, partition_id, dimension_index)::ActorSpawnInfo
|
|
FROM actors WHERE actors.id = in_id
|
|
LIMIT 1);
|
|
end
|
|
$function$
|
|
|
|
|
|
-- fix_broken_harkonnen_players_due_to_fooled_thufir() -> void
|
|
-- oid: 58264 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.fix_broken_harkonnen_players_due_to_fooled_thufir()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
|
|
-- Dropping tables due to them being created in temp_backup_tables.sql
|
|
drop table if exists da_6358_pre_broken_players;
|
|
drop table if exists da_6358_broken_players_12400;
|
|
drop table if exists da_6358_broken_players_1300;
|
|
|
|
---Fix players that are in a broken state but haven't been blocked yet
|
|
--Tag combo to check for:
|
|
--DialogueFlags.Factions.Hark_ThufirBetrayedComplete
|
|
--DialogueFlags.Faction.FooledThufir
|
|
--PlayerIsFactionTier Harkonnen 5
|
|
--TO FIX:
|
|
--Remove DialogueFlags.Faction.FooledThufir
|
|
create table if not exists da_6358_pre_broken_players as
|
|
select pt.account_id from player_tags pt
|
|
group by pt.account_id
|
|
HAVING array_agg(DISTINCT tag) @> ARRAY['DialogueFlags.Factions.Hark_ThufirBetrayedComplete', 'DialogueFlags.Faction.FooledThufir', 'Faction.Harkonnen.Tier5'];
|
|
|
|
delete from player_tags pt using da_6358_pre_broken_players where pt.account_id = da_6358_pre_broken_players.account_id and pt.tag = 'DialogueFlags.Faction.FooledThufir';
|
|
|
|
---Fix players that are in a broken state since 1.2.40
|
|
---Tag combo to check for:
|
|
---DialogueFlags.Factions.Hark_ThufirBetrayedComplete
|
|
---DialogueFlags.Faction.FooledThufir
|
|
---Contract.Tracking.FactionStory.R4C6Completed
|
|
---PlayerIsFactionTier Harkonnen 4
|
|
---TO FIX:
|
|
---Remove DialogueFlags.Faction.FooledThufir
|
|
---Promote player to Harkonnen 5
|
|
|
|
create table if not exists da_6358_broken_players_12400 as
|
|
with broken_accounts as (
|
|
select pt.account_id
|
|
from player_tags pt
|
|
group by pt.account_id
|
|
having array_agg(distinct pt.tag) @> array[
|
|
'DialogueFlags.Factions.Hark_ThufirBetrayedComplete',
|
|
'DialogueFlags.Faction.FooledThufir',
|
|
'Contract.Tracking.FactionStory.R4C6Completed',
|
|
'Faction.Harkonnen.Tier4'
|
|
]
|
|
and not array_agg(distinct pt.tag) && array['Faction.Harkonnen.Tier5']
|
|
),
|
|
one_state_row_per_account as (
|
|
-- If player_state can theoretically have duplicates per account_id,
|
|
-- pick one deterministically.
|
|
select distinct on (ps.account_id)
|
|
ps.account_id,
|
|
ps.player_controller_id
|
|
from player_state ps
|
|
join broken_accounts ba on ba.account_id = ps.account_id
|
|
order by ps.account_id, ps.player_controller_id desc
|
|
)
|
|
select
|
|
s.account_id,
|
|
s.player_controller_id,
|
|
a.properties as backup_properties
|
|
from one_state_row_per_account s
|
|
join actors a on a.id = s.player_controller_id;
|
|
|
|
INSERT INTO player_tags (account_id, tag)
|
|
SELECT account_id, 'Faction.Harkonnen.Tier5' as tag
|
|
FROM da_6358_broken_players_12400
|
|
ON CONFLICT (account_id, tag) DO NOTHING;
|
|
|
|
delete from player_tags pt using da_6358_broken_players_12400 where pt.account_id = da_6358_broken_players_12400.account_id and pt.tag = 'DialogueFlags.Faction.FooledThufir';
|
|
UPDATE actors
|
|
SET properties = jsonb_set(
|
|
properties,
|
|
'{FactionPlayerComponent,m_FactionDataArray}',
|
|
(
|
|
SELECT coalesce(
|
|
jsonb_agg(
|
|
CASE
|
|
WHEN elem->'Faction'->>'Name' = 'Harkonnen'
|
|
THEN jsonb_set(elem, '{ReputationAmount}', '2000'::jsonb)
|
|
ELSE elem
|
|
END
|
|
),
|
|
'[]'::jsonb
|
|
)
|
|
FROM jsonb_array_elements(properties->'FactionPlayerComponent'->'m_FactionDataArray') AS t(elem)
|
|
)
|
|
)
|
|
FROM da_6358_broken_players_12400 b12400
|
|
WHERE b12400.player_controller_id = actors.id;
|
|
|
|
---Fix players that are in a broken state in live aka 1.3.0
|
|
---Tag combo to check for:
|
|
---DialogueFlags.Factions.Hark_ThufirBetrayedComplete
|
|
---Contract.Tracking.FactionStory.R4C6Completed
|
|
---PlayerIsFactionTier Harkonnen 4
|
|
---NOT DialogueFlags.Faction.FooledThufir
|
|
create table if not exists da_6358_broken_players_1300 as
|
|
with broken_accounts as (
|
|
select pt.account_id
|
|
from player_tags pt
|
|
group by pt.account_id
|
|
HAVING array_agg(DISTINCT tag) @> ARRAY ['DialogueFlags.Factions.Hark_ThufirBetrayedComplete', 'Contract.Tracking.FactionStory.R4C6Completed', 'Faction.Harkonnen.Tier4']
|
|
and not array_agg(distinct tag) && array['DialogueFlags.Faction.FooledThufir', 'Faction.Harkonnen.Tier5'] -- Since Tier4 players can also have Tier5 we need to exclude that
|
|
),
|
|
one_state_row_per_account as (
|
|
-- If player_state can theoretically have duplicates per account_id,
|
|
-- pick one deterministically.
|
|
select distinct on (ps.account_id)
|
|
ps.account_id,
|
|
ps.player_controller_id
|
|
from player_state ps
|
|
join broken_accounts ba on ba.account_id = ps.account_id
|
|
order by ps.account_id, ps.player_controller_id desc
|
|
)
|
|
select
|
|
s.account_id,
|
|
s.player_controller_id,
|
|
a.properties as backup_properties
|
|
from one_state_row_per_account s
|
|
join actors a on a.id = s.player_controller_id;
|
|
|
|
INSERT INTO player_tags (account_id, tag)
|
|
SELECT account_id, 'Faction.Harkonnen.Tier5' as tag
|
|
FROM da_6358_broken_players_1300
|
|
ON CONFLICT (account_id, tag) DO NOTHING;
|
|
|
|
UPDATE actors
|
|
SET properties = jsonb_set(
|
|
properties,
|
|
'{FactionPlayerComponent,m_FactionDataArray}',
|
|
(
|
|
SELECT coalesce(
|
|
jsonb_agg(
|
|
CASE
|
|
WHEN elem->'Faction'->>'Name' = 'Harkonnen'
|
|
THEN jsonb_set(elem, '{ReputationAmount}', '2000'::jsonb)
|
|
ELSE elem
|
|
END
|
|
),
|
|
'[]'::jsonb
|
|
)
|
|
FROM jsonb_array_elements(properties->'FactionPlayerComponent'->'m_FactionDataArray') AS t(elem)
|
|
)
|
|
)
|
|
FROM da_6358_broken_players_1300 b1300
|
|
WHERE b1300.player_controller_id = actors.id;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- flag_player_as_cheater(in_account_id bigint, in_cheat_type dune.cheat_type_enum) -> void
|
|
-- oid: 58265 kind: FUNCTION category: anticheat
|
|
|
|
CREATE OR REPLACE FUNCTION dune.flag_player_as_cheater(in_account_id bigint, in_cheat_type dune.cheat_type_enum)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
v_FLS_id TEXT;
|
|
BEGIN
|
|
SELECT acc."user"
|
|
INTO v_FLS_id
|
|
FROM accounts acc
|
|
WHERE acc.id = in_account_id
|
|
LIMIT 1;
|
|
|
|
PERFORM log_cheating(v_FLS_id, in_cheat_type);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- gather_ownerless_actors_on_server(in_server_info dune.serverinfo) -> SETOF dune.actorspawninfo
|
|
-- oid: 58266 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.gather_ownerless_actors_on_server(in_server_info dune.serverinfo)
|
|
RETURNS SETOF dune.actorspawninfo
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT a.id, a.class as class_name, a.transform, a.partition_id, a.dimension_index FROM actors as a
|
|
WHERE a.owner_account_id is null AND server_info_match(a, in_server_info);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- gather_player_linked_actors(in_player_pawn_id bigint) -> SETOF dune.actorspawninfo
|
|
-- oid: 58267 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.gather_player_linked_actors(in_player_pawn_id bigint)
|
|
RETURNS SETOF dune.actorspawninfo
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
select actors.id, actors.class as class_name, actors.transform, actors.partition_id, actors.dimension_index
|
|
from actors
|
|
left join actor_state on actor_state.actor_id = actors.id
|
|
where actors.id in (select id from get_traveling_non_player_actor_ids(in_player_pawn_id)) and actor_state.state = 'Travel' and actors.owner_account_id is null
|
|
order by actors.id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- gather_removed_accounts_that_left_orphaned_actors_on_server(in_server_info dune.serverinfo) -> TABLE(account_id bigint, removal_reason text, actors_left dune.orphanedplayeractorinfo[])
|
|
-- oid: 58268 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.gather_removed_accounts_that_left_orphaned_actors_on_server(in_server_info dune.serverinfo)
|
|
RETURNS TABLE(account_id bigint, removal_reason text, actors_left dune.orphanedplayeractorinfo[])
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return query with
|
|
orphaned_actors_per_account as (
|
|
SELECT
|
|
a.owner_account_id as account_id,
|
|
array_agg((a.id, a.class)::OrphanedPlayerActorInfo) as actors_left
|
|
FROM actors as a
|
|
WHERE
|
|
-- not is null instead of is not null to match the index expression
|
|
not a.owner_account_id is null
|
|
AND NOT EXISTS(select 1 from accounts where id=owner_account_id)
|
|
AND server_info_match(a, in_server_info)
|
|
GROUP BY a.owner_account_id
|
|
)
|
|
select orphans.account_id, log.reason, orphans.actors_left
|
|
from orphaned_actors_per_account as orphans left join account_removal_log as log using (account_id);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_account_actor_ids(in_account_id bigint) -> dune.playeractorids
|
|
-- oid: 58269 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_account_actor_ids(in_account_id bigint)
|
|
RETURNS dune.playeractorids
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return (
|
|
select (player_controller_id, player_state_id, player_pawn_id)::PlayerActorIds from player_state
|
|
where account_id = in_account_id
|
|
limit 1
|
|
);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_active_servers_for_gateway() -> TABLE(server_id text, map text, partition_id bigint, dimension_index integer, game_addr inet, game_port integer, revision integer)
|
|
-- oid: 58270 kind: FUNCTION category: server
|
|
-- comment: Used by the gateway service to monitor for active servers.
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_active_servers_for_gateway()
|
|
RETURNS TABLE(server_id text, map text, partition_id bigint, dimension_index integer, game_addr inet, game_port integer, revision integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
-- If we have no partitions, assume dimension 0
|
|
return query select fs.server_id, fs.map, wp.partition_id, coalesce(wp.dimension_index, 0), fs.game_addr, fs.game_port, fs.revision from active_server_ids as asi left join world_partition as wp on asi.server_id = wp.server_id join farm_state as fs on fs.server_id = asi.server_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_actor_server_info(in_id bigint) -> dune.serverinfo
|
|
-- oid: 58271 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_actor_server_info(in_id bigint)
|
|
RETURNS dune.serverinfo
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return (select (map, partition_id, dimension_index)::ServerInfo from actors where id=in_id limit 1);
|
|
end
|
|
$function$
|
|
|
|
|
|
-- get_actors_location_data_with_permission(in_actor_ids bigint[]) -> SETOF dune.actorpermissionlocationdata
|
|
-- oid: 58272 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_actors_location_data_with_permission(in_actor_ids bigint[])
|
|
RETURNS SETOF dune.actorpermissionlocationdata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT actors.id, actors.partition_id, actors.map, actors.dimension_index, actors.transform
|
|
FROM actors
|
|
WHERE actors.id = ANY(in_actor_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_demo_players() -> TABLE(fls_ids text)
|
|
-- oid: 58273 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_demo_players()
|
|
RETURNS TABLE(fls_ids text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT fls_id
|
|
FROM demo_users
|
|
WHERE demo_playtime_seconds IS NOT NULL;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_faction_members() -> TABLE(player_id bigint, fls_id text, faction_id smallint)
|
|
-- oid: 58274 kind: FUNCTION category: faction
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_faction_members()
|
|
RETURNS TABLE(player_id bigint, fls_id text, faction_id smallint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT ps.player_controller_id as player_id, acc.user as fls_id, f.faction_id
|
|
FROM accounts acc
|
|
LEFT JOIN player_state ps ON acc.id = ps.account_id
|
|
RIGHT JOIN player_faction f ON ps.player_controller_id = f.actor_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_guild_members() -> TABLE(player_id bigint, fls_id text, guild_id bigint)
|
|
-- oid: 58275 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_guild_members()
|
|
RETURNS TABLE(player_id bigint, fls_id text, guild_id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT gm.player_id, acc.user, gm.guild_id
|
|
FROM accounts acc
|
|
LEFT JOIN player_state ps ON acc.id = ps.account_id
|
|
RIGHT JOIN guild_members gm ON ps.player_controller_id = gm.player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_online_or_recently_disconnected_player_online_state() -> SETOF dune.playeronlinestateentry
|
|
-- oid: 58276 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_online_or_recently_disconnected_player_online_state()
|
|
RETURNS SETOF dune.playeronlinestateentry
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT actors.id, player_state.character_name, (actors.map, actors.partition_id, actors.dimension_index)::ServerInfo, (player_state.last_avatar_activity AT TIME ZONE 'UTC')::TIMESTAMP, player_state.online_status
|
|
FROM actors
|
|
JOIN player_state ON player_state.player_controller_id = actors.id
|
|
WHERE (player_state.online_status = 'Online'
|
|
or player_state.last_avatar_activity > NOW() - INTERVAL '1 minutes' );
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_parties() -> TABLE(party_id bigint, player_id bigint, player_name text, party_leader_id bigint, platform_session_id text, platform_name text, platform_players_count integer)
|
|
-- oid: 58277 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_parties()
|
|
RETURNS TABLE(party_id bigint, player_id bigint, player_name text, party_leader_id bigint, platform_session_id text, platform_name text, platform_players_count integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT
|
|
parties.party_id,
|
|
party_members.player_id,
|
|
player_state.character_name,
|
|
parties.party_leader_id,
|
|
platform_parties_mapping.platform_session_id,
|
|
platform_parties_mapping.platform_name,
|
|
platform_parties_mapping.num_of_players
|
|
FROM party_members
|
|
JOIN parties ON party_members.party_id = parties.party_id
|
|
JOIN player_state ON player_state.player_controller_id = party_members.player_id
|
|
LEFT JOIN platform_parties_mapping ON platform_parties_mapping.dune_party_id = parties.party_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_party_invites() -> TABLE(invite_id bigint, party_id bigint, sender_player_id bigint, sender_name text, player_id bigint, player_name text, invite_sent_timespan bigint)
|
|
-- oid: 58278 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_party_invites()
|
|
RETURNS TABLE(invite_id bigint, party_id bigint, sender_player_id bigint, sender_name text, player_id bigint, player_name text, invite_sent_timespan bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT party_invites.invite_id, party_invites.party_id, party_invites.sender_player_id, sender_player_state.character_name, party_invites.player_id, player_state.character_name, party_invites.invite_sent_timespan
|
|
FROM party_invites
|
|
JOIN player_state ON player_state.player_controller_id = party_invites.player_id
|
|
JOIN player_state AS sender_player_state ON sender_player_state.player_controller_id = party_invites.sender_player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_party_members() -> TABLE(player_id bigint, fls_id text, party_id bigint)
|
|
-- oid: 58279 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_party_members()
|
|
RETURNS TABLE(player_id bigint, fls_id text, party_id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT pm.player_id, acc.user, pm.party_id
|
|
FROM party_members pm
|
|
LEFT JOIN player_state ps ON ps.player_controller_id = pm.player_id
|
|
LEFT JOIN accounts acc ON acc.id = ps.account_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_player_character_home_dimensions() -> TABLE(fls_id text, home_dimension integer)
|
|
-- oid: 58280 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_player_character_home_dimensions()
|
|
RETURNS TABLE(fls_id text, home_dimension integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT accounts.user as fls_id, player_state.home_dimension_index as home_dimension
|
|
FROM accounts
|
|
LEFT JOIN player_state on player_state.account_id = accounts.id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_player_in_guild_online_state(in_guild_id bigint) -> SETOF dune.playeronlinestateentry
|
|
-- oid: 58281 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_player_in_guild_online_state(in_guild_id bigint)
|
|
RETURNS SETOF dune.playeronlinestateentry
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT actors.id, player_state.character_name, (actors.map, actors.partition_id, actors.dimension_index)::ServerInfo, (player_state.last_avatar_activity AT TIME ZONE 'UTC')::TIMESTAMP, player_state.online_status
|
|
FROM actors
|
|
JOIN player_state ON player_state.player_controller_id = actors.id
|
|
JOIN guild_members ON guild_members.player_id = actors.id
|
|
WHERE guild_members.guild_id = in_guild_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_player_travel_states() -> TABLE(fls_id text, login_target_dimension_index integer)
|
|
-- oid: 58282 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_player_travel_states()
|
|
RETURNS TABLE(fls_id text, login_target_dimension_index integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
RETURN query SELECT pts.fls_id, pts.login_target_dimension_index FROM player_travel_state AS pts;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- get_all_tutorial_entries(in_player_id bigint) -> TABLE(tutorial_id smallint, tutorial_state smallint)
|
|
-- oid: 58283 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_tutorial_entries(in_player_id bigint)
|
|
RETURNS TABLE(tutorial_id smallint, tutorial_state smallint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT tutorial_per_player.tutorial_id, tutorial_per_player.tutorial_state FROM tutorial_per_player WHERE tutorial_per_player.player_id = in_player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_all_unresolved_character_imports() -> TABLE(flsid text, importstate dune.transferimportstate, lastupdatetime timestamp with time zone)
|
|
-- oid: 58284 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_all_unresolved_character_imports()
|
|
RETURNS TABLE(flsid text, importstate dune.transferimportstate, lastupdatetime timestamp with time zone)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT ti.fls_id, ti.transfer_state, ti.last_update
|
|
FROM character_transfer_imports ti;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- get_applied_patches() -> SETOF text
|
|
-- oid: 58285 kind: FUNCTION category: schema_meta
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_applied_patches()
|
|
RETURNS SETOF text
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select "name" from applied_patches order by "date";
|
|
$function$
|
|
|
|
|
|
-- get_battlegroup_close_date() -> timestamp without time zone
|
|
-- oid: 58286 kind: FUNCTION category: battlegroup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_battlegroup_close_date()
|
|
RETURNS timestamp without time zone
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN (SELECT farm_variables.battlegroup_close_date from farm_variables);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_best_dungeon_completion(in_dungeon_id text) -> TABLE(out_difficulty integer, out_duration_ms integer, out_players_names text[])
|
|
-- oid: 58287 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_best_dungeon_completion(in_dungeon_id text)
|
|
RETURNS TABLE(out_difficulty integer, out_duration_ms integer, out_players_names text[])
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
RETURN QUERY SELECT
|
|
d.difficulty,
|
|
d.duration_ms,
|
|
COALESCE((SELECT array_agg(COALESCE(ps.character_name, ''))
|
|
FROM player_state as ps
|
|
FULL JOIN dungeon_completion_players as dcp ON dcp.player_id = ps.player_controller_id
|
|
WHERE dcp.completion_id = d.completion_id), ARRAY[]::TEXT[])
|
|
FROM dungeon_completion as d
|
|
WHERE d.dungeon_id = in_dungeon_id
|
|
ORDER BY d.difficulty DESC, d.players_num ASC, d.duration_ms ASC, d.completion_id ASC
|
|
LIMIT 1;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- get_best_dungeons_completions_for_player(in_player_id bigint) -> TABLE(out_dungeon_id text, out_difficulty integer, out_duration_ms integer, out_players_num smallint)
|
|
-- oid: 58288 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_best_dungeons_completions_for_player(in_player_id bigint)
|
|
RETURNS TABLE(out_dungeon_id text, out_difficulty integer, out_duration_ms integer, out_players_num smallint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
RETURN QUERY SELECT DISTINCT ON (d.dungeon_id) d.dungeon_id, d.difficulty, d.duration_ms, d.players_num
|
|
FROM dungeon_completion as d
|
|
INNER JOIN dungeon_completion_players as p ON p.completion_id = d.completion_id
|
|
WHERE p.player_id = in_player_id
|
|
ORDER BY d.dungeon_id, d.difficulty DESC, d.players_num ASC, d.duration_ms ASC, d.completion_id ASC;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- get_building_blueprint_copy_data(in_building_blueprint_id bigint) -> dune.buildingblueprintgetcopydata
|
|
-- oid: 58289 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_building_blueprint_copy_data(in_building_blueprint_id bigint)
|
|
RETURNS dune.buildingblueprintgetcopydata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
buildings_array BuildingBlueprintItem[];
|
|
placeables_array BuildingBlueprintPlaceableItem[];
|
|
pentashields_array BuildingBlueprintPentashieldItem[];
|
|
BEGIN
|
|
-- All Building Pieces
|
|
SELECT array_agg((instance_id, building_type, transform, provides_stability, health, hologram)::BuildingBlueprintItem)
|
|
into buildings_array
|
|
FROM building_blueprint_instances
|
|
WHERE building_blueprint_id = in_building_blueprint_id;
|
|
|
|
-- All Placeables
|
|
SELECT array_agg((placeable_id, building_type, transform, hologram)::BuildingBlueprintPlaceableItem)
|
|
into placeables_array
|
|
FROM building_blueprint_placeables
|
|
WHERE building_blueprint_id = in_building_blueprint_id;
|
|
|
|
-- Pentashields
|
|
SELECT array_agg((placeable_id, scale)::BuildingBlueprintPentashieldItem)
|
|
into pentashields_array
|
|
FROM building_blueprint_pentashields
|
|
WHERE building_blueprint_id = in_building_blueprint_id;
|
|
|
|
return ROW(buildings_array, placeables_array, pentashields_array)::BuildingBlueprintGetCopyData;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_building_favorites(in_account_id bigint) -> TABLE(building_types text[])
|
|
-- oid: 58290 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_building_favorites(in_account_id bigint)
|
|
RETURNS TABLE(building_types text[])
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT building_favorites.building_types FROM building_favorites WHERE account_id = in_account_id;
|
|
END; $function$
|
|
|
|
|
|
-- get_building_id(in_actor_id bigint, in_class text) -> dune.buildinggetidcomposite
|
|
-- oid: 58291 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_building_id(in_actor_id bigint, in_class text)
|
|
RETURNS dune.buildinggetidcomposite
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF not exists(select 1 from buildings where "id" = in_actor_id) THEN
|
|
if in_actor_id is null or in_actor_id = 0 then
|
|
in_actor_id := (SELECT assign_actor_id(in_class));
|
|
end if;
|
|
|
|
INSERT INTO buildings("id") VALUES(in_actor_id);
|
|
END IF;
|
|
|
|
return ROW(in_actor_id)::BuildingGetIdComposite;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_character_import_state(in_fls_id text) -> dune.transferimportstate
|
|
-- oid: 58292 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_character_import_state(in_fls_id text)
|
|
RETURNS dune.transferimportstate
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
v_state TransferImportState;
|
|
BEGIN
|
|
SELECT transfer_state INTO v_state FROM character_transfer_imports WHERE fls_id = in_fls_id;
|
|
RETURN v_state;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- get_consumed_lore_pickups(in_actor_id bigint, in_use_temporary boolean) -> SETOF bit
|
|
-- oid: 58294 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_consumed_lore_pickups(in_actor_id bigint, in_use_temporary boolean)
|
|
RETURNS SETOF bit
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF in_use_temporary THEN
|
|
RETURN query
|
|
SELECT consumed_bit_array
|
|
FROM consumed_temporary_per_player_lore
|
|
WHERE actor_id = in_actor_id;
|
|
ELSE
|
|
RETURN query
|
|
SELECT consumed_bit_array
|
|
FROM consumed_per_player_lore
|
|
WHERE actor_id = in_actor_id;
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_controller_id_from_platform_id(in_platform_id text) -> bigint
|
|
-- oid: 58295 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_controller_id_from_platform_id(in_platform_id text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_controller_id BIGINT;
|
|
BEGIN
|
|
SELECT ps.player_controller_id
|
|
INTO out_controller_id
|
|
FROM accounts acc LEFT JOIN player_state ps ON acc.id=ps.account_id
|
|
WHERE acc.platform_id = in_platform_id
|
|
LIMIT 1;
|
|
RETURN out_controller_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_dune_exchange_accesspoint_id(in_exchange_id bigint, in_name text) -> bigint
|
|
-- oid: 58296 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_dune_exchange_accesspoint_id(in_exchange_id bigint, in_name text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
new_ap_id BIGINT;
|
|
ap_id BIGINT;
|
|
BEGIN
|
|
INSERT INTO dune_exchange_accesspoints(exchange_id, name) VALUES(in_exchange_id, in_name) ON CONFLICT DO NOTHING RETURNING id INTO new_ap_id;
|
|
SELECT INTO ap_id COALESCE(new_ap_id, id) FROM dune_exchange_accesspoints WHERE exchange_id = in_exchange_id AND name = in_name;
|
|
|
|
return ap_id;
|
|
END $function$
|
|
|
|
|
|
-- get_dune_exchange_data(in_exchange_id bigint, in_controller_id bigint) -> dune.loadexchangedataresult
|
|
-- oid: 58297 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_dune_exchange_data(in_exchange_id bigint, in_controller_id bigint)
|
|
RETURNS dune.loadexchangedataresult
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result LoadExchangeDataResult;
|
|
BEGIN
|
|
SELECT INTO result.exchange_name exchange_name FROM dune_exchanges WHERE id=in_exchange_id;
|
|
SELECT INTO result.used_order_slots get_dune_exchange_used_order_slots(in_controller_id);
|
|
|
|
RETURN result;
|
|
END $function$
|
|
|
|
|
|
-- get_dune_exchange_id(in_name text) -> bigint
|
|
-- oid: 58298 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_dune_exchange_id(in_name text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
new_exchange_id BIGINT;
|
|
exchange_id BIGINT;
|
|
BEGIN
|
|
INSERT INTO dune_exchanges(exchange_name, inventory_id) VALUES(in_name, NULL) ON CONFLICT DO NOTHING RETURNING id INTO new_exchange_id;
|
|
SELECT INTO exchange_id COALESCE(new_exchange_id, id) FROM dune_exchanges WHERE exchange_name = in_name;
|
|
RETURN exchange_id;
|
|
END $function$
|
|
|
|
|
|
-- get_dune_exchange_used_order_slots(in_controller_id bigint) -> integer
|
|
-- oid: 58299 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_dune_exchange_used_order_slots(in_controller_id bigint)
|
|
RETURNS integer
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result INT;
|
|
BEGIN
|
|
SELECT INTO result COUNT(*) FROM dune_exchange_orders where owner_id=in_controller_id AND item_id IS NOT NULL;
|
|
|
|
RETURN result;
|
|
END $function$
|
|
|
|
|
|
-- get_exchange_inventory_id(in_exchange_id bigint) -> bigint
|
|
-- oid: 58300 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_exchange_inventory_id(in_exchange_id bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
inv_id BIGINT;
|
|
BEGIN
|
|
SELECT INTO inv_id id FROM inventories WHERE "exchange_id" = in_exchange_id;
|
|
IF inv_id IS NULL THEN
|
|
INSERT INTO inventories("id", exchange_id) VALUES(DEFAULT, in_exchange_id) RETURNING id INTO inv_id;
|
|
END IF;
|
|
RETURN inv_id;
|
|
END $function$
|
|
|
|
|
|
-- get_exchange_orders_by_mask(in_mask integer, in_depth smallint) -> SETOF bigint
|
|
-- oid: 58301 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_exchange_orders_by_mask(in_mask integer, in_depth smallint)
|
|
RETURNS SETOF bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
check_mask INT;
|
|
check_shift INT;
|
|
BEGIN
|
|
check_shift := (4 - in_depth) * 8;
|
|
check_mask := (in_mask >> check_shift);
|
|
RETURN query SELECT id FROM dune_exchange_orders WHERE category_depth >= in_depth AND (category_mask >> check_shift) = check_mask FOR SHARE;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_exchange_sell_orders(in_id bigint, in_exchange_id bigint, in_min_item_price bigint, in_max_item_price bigint, in_template_id text, in_mask integer, in_depth smallint) -> TABLE(id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, template_id text, stack_size bigint, initial_stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
-- oid: 58302 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_exchange_sell_orders(in_id bigint, in_exchange_id bigint, in_min_item_price bigint, in_max_item_price bigint, in_template_id text, in_mask integer, in_depth smallint)
|
|
RETURNS TABLE(id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, template_id text, stack_size bigint, initial_stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
RETURN query
|
|
SELECT ord.id, ord.revision, ord.expiration_time, ord.access_point_id, ap.name, ord.owner_id, item.template_id, item.stack_size, sord.initial_stack_size, ord.item_price, ord.quality_level, ord.durability_cur, ord.durability_max, item.stats
|
|
FROM dune_exchange_orders ord
|
|
JOIN dune_exchange_sell_orders sord ON (ord.id = sord.order_id)
|
|
JOIN items item ON (ord.item_id = item.id)
|
|
JOIN dune_exchange_accesspoints ap ON (ord.access_point_id = ap.id)
|
|
WHERE (in_id IS NOT NULL AND ord.id = in_id) OR
|
|
(in_id IS NULL AND ord.exchange_id = in_exchange_id AND ord.item_price >= in_min_item_price AND (in_max_item_price <= 0 OR ord.item_price <= in_max_item_price) AND
|
|
((in_template_id IS NOT NULL AND ord.template_id = in_template_id) OR
|
|
(in_template_id IS NULL AND ord.id IN (SELECT * FROM get_exchange_orders_by_mask(in_mask, in_depth))))
|
|
)
|
|
FOR SHARE;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_exchange_sell_orders_by_item_type(in_exchange_id bigint, in_template_ids text[]) -> TABLE(id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, template_id text, stack_size bigint, initial_stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
-- oid: 58303 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_exchange_sell_orders_by_item_type(in_exchange_id bigint, in_template_ids text[])
|
|
RETURNS TABLE(id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, template_id text, stack_size bigint, initial_stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
RETURN query
|
|
SELECT ord.id, ord.revision, ord.expiration_time, ord.access_point_id, ap.name, ord.owner_id, item.template_id, item.stack_size, sord.initial_stack_size, ord.item_price, ord.quality_level, ord.durability_cur, ord.durability_max, item.stats
|
|
FROM dune_exchange_orders ord
|
|
JOIN dune_exchange_sell_orders sord ON (ord.id = sord.order_id)
|
|
JOIN items item ON (ord.item_id = item.id)
|
|
JOIN dune_exchange_accesspoints ap ON (ord.access_point_id = ap.id)
|
|
WHERE ord.exchange_id = in_exchange_id AND ord.template_id = ANY(in_template_ids)
|
|
FOR SHARE;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_exchange_sell_orders_by_owner(in_exchange_id bigint, in_owner_id bigint) -> TABLE(id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, template_id text, stack_size bigint, initial_stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
-- oid: 58304 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_exchange_sell_orders_by_owner(in_exchange_id bigint, in_owner_id bigint)
|
|
RETURNS TABLE(id bigint, revision bigint, expiration_time bigint, access_point_id bigint, ap_name text, owner_id bigint, template_id text, stack_size bigint, initial_stack_size bigint, item_price bigint, quality_level bigint, durability_cur real, durability_max real, dynamic_stats jsonb)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
RETURN query
|
|
SELECT ord.id, ord.revision, ord.expiration_time, ord.access_point_id, ap.name, ord.owner_id, item.template_id, item.stack_size, sord.initial_stack_size, ord.item_price, ord.quality_level, ord.durability_cur, ord.durability_max, item.stats
|
|
FROM dune_exchange_orders ord
|
|
JOIN dune_exchange_sell_orders sord ON (ord.id = sord.order_id)
|
|
JOIN items item ON (ord.item_id = item.id)
|
|
JOIN dune_exchange_accesspoints ap ON (ord.access_point_id = ap.id)
|
|
WHERE ord.owner_id = in_owner_id
|
|
FOR SHARE;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_farm_state() -> TABLE(server_id text, farm_id text, outgoing_s2s_connections integer, incoming_s2s_connections integer, connected_players integer, igw_addr inet, igw_port integer, game_addr inet, game_port integer, ready boolean, alive boolean, map text, revision integer)
|
|
-- oid: 58305 kind: FUNCTION category: farm
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_farm_state()
|
|
RETURNS TABLE(server_id text, farm_id text, outgoing_s2s_connections integer, incoming_s2s_connections integer, connected_players integer, igw_addr inet, igw_port integer, game_addr inet, game_port integer, ready boolean, alive boolean, map text, revision integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
RETURN QUERY SELECT fs.server_id, fs.farm_id, fs.outgoing_s2s_connections, fs.incoming_s2s_connections, fs.connected_players, fs.igw_addr, fs.igw_port, fs.game_addr, fs.game_port, fs.ready, fs.alive, fs.map, fs.revision FROM farm_state as fs
|
|
JOIN active_server_ids USING(server_id);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_friends_search(in_player_name text, in_max_players_count integer) -> TABLE(player_id bigint, character_name text, funcom_id text, platform_id text, platform_name text)
|
|
-- oid: 58306 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_friends_search(in_player_name text, in_max_players_count integer)
|
|
RETURNS TABLE(player_id bigint, character_name text, funcom_id text, platform_id text, platform_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT player_state.player_controller_id, player_state.character_name, accounts.funcom_id, accounts.platform_id, accounts.platform_name
|
|
FROM player_state
|
|
JOIN accounts ON player_state.account_id = accounts.id
|
|
WHERE player_state.character_name ILIKE '%' || in_player_name || '%'
|
|
ORDER BY ext.SIMILARITY(player_state.character_name, in_player_name) DESC
|
|
LIMIT in_max_players_count;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_guild_data(in_guild_id bigint) -> TABLE(guild_name text, guild_faction_id smallint, guild_description text)
|
|
-- oid: 58307 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_guild_data(in_guild_id bigint)
|
|
RETURNS TABLE(guild_name text, guild_faction_id smallint, guild_description text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT guilds.guild_name, guilds.guild_faction, guilds.guild_description
|
|
FROM guilds
|
|
WHERE guild_id = in_guild_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_guild_data_for_player(in_player_id bigint) -> TABLE(guild_id bigint, guild_factions_id smallint, guild_name text, guild_description text, player_id bigint, role_id smallint, player_faction_id smallint)
|
|
-- oid: 58308 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_guild_data_for_player(in_player_id bigint)
|
|
RETURNS TABLE(guild_id bigint, guild_factions_id smallint, guild_name text, guild_description text, player_id bigint, role_id smallint, player_faction_id smallint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT guilds.guild_id, guilds.guild_faction, guilds.guild_name, guilds.guild_description, guild_members.player_id, guild_members.role_id, player_faction.faction_id
|
|
FROM guilds JOIN guild_members on (guilds.guild_id = guild_members.guild_id)
|
|
LEFT JOIN player_faction on player_faction.actor_id = guild_members.player_id
|
|
WHERE guild_members.player_id = in_player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_guild_for_player(in_player_id bigint) -> bigint
|
|
-- oid: 58309 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_guild_for_player(in_player_id bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_guild_id integer;
|
|
BEGIN
|
|
SELECT guild_id FROM guild_members WHERE player_id = in_player_id INTO found_guild_id;
|
|
IF NOT FOUND THEN
|
|
RETURN 0;
|
|
END IF;
|
|
RETURN found_guild_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_guild_invites(in_guild_id bigint) -> TABLE(invite_id bigint, player_id bigint, sender_player_id bigint, invite_sent_timespan bigint, character_name text, sender_character_name text)
|
|
-- oid: 58310 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_guild_invites(in_guild_id bigint)
|
|
RETURNS TABLE(invite_id bigint, player_id bigint, sender_player_id bigint, invite_sent_timespan bigint, character_name text, sender_character_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT guild_invites.invite_id, guild_invites.player_id, guild_invites.sender_player_id, guild_invites.invite_sent_timespan, player_state.character_name, sender_player_state.character_name AS sender_character_name
|
|
FROM guild_invites
|
|
JOIN player_state ON player_state.player_controller_id = guild_invites.player_id
|
|
JOIN player_state AS sender_player_state ON sender_player_state.player_controller_id = guild_invites.sender_player_id
|
|
WHERE guild_id = in_guild_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_guild_members(in_guild_id bigint) -> TABLE(player_id bigint, role_id smallint, player_faction_id smallint)
|
|
-- oid: 58311 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_guild_members(in_guild_id bigint)
|
|
RETURNS TABLE(player_id bigint, role_id smallint, player_faction_id smallint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT guild_members.player_id, guild_members.role_id, player_faction.faction_id
|
|
FROM guild_members
|
|
LEFT JOIN player_faction ON player_faction.actor_id = guild_members.player_id
|
|
WHERE guild_id = in_guild_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_inventory_data(in_inventory_id bigint) -> dune.inventorydata
|
|
-- oid: 58312 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_inventory_data(in_inventory_id bigint)
|
|
RETURNS dune.inventorydata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
inventory_data InventoryData;
|
|
BEGIN
|
|
SELECT INTO
|
|
inventory_data.inventory_id, inventory_data.inventory_type, inventory_data.max_item_count, inventory_data.max_item_volume
|
|
id, inventory_type, max_item_count, max_item_volume
|
|
FROM inventories
|
|
WHERE id = in_inventory_id;
|
|
|
|
RETURN inventory_data;
|
|
END $function$
|
|
|
|
|
|
-- get_inventory_id(in_actor_id bigint, in_component_name_hash integer) -> bigint
|
|
-- oid: 58313 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_inventory_id(in_actor_id bigint, in_component_name_hash integer)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
inv_id BIGINT;
|
|
BEGIN
|
|
SELECT INTO inv_id inventory_id FROM actor_inventories ai JOIN inventories i ON (ai.inventory_id = i.id) WHERE i.actor_id = in_actor_id AND ai.component_name_hash = in_component_name_hash;
|
|
IF inv_id IS NULL THEN
|
|
INSERT INTO inventories("id", "actor_id") VALUES(DEFAULT, in_actor_id) RETURNING id INTO inv_id;
|
|
INSERT INTO actor_inventories("inventory_id", "component_name_hash") VALUES(inv_id, in_component_name_hash);
|
|
END IF;
|
|
RETURN inv_id;
|
|
END $function$
|
|
|
|
|
|
-- get_items_to_remove(items_to_remove text[]) -> text[]
|
|
-- oid: 58314 kind: FUNCTION category: items_purge
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_items_to_remove(items_to_remove text[])
|
|
RETURNS text[]
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
declare
|
|
result text[];
|
|
begin
|
|
select array(
|
|
select unnest(items_to_remove)
|
|
except
|
|
select name
|
|
from removed_items
|
|
) into result;
|
|
return result;
|
|
end;
|
|
$function$
|
|
|
|
|
|
-- get_landclaim_segments(in_totem_id bigint) -> TABLE(grid_location_x bigint, grid_location_y bigint)
|
|
-- oid: 58315 kind: FUNCTION category: landclaim
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_landclaim_segments(in_totem_id bigint)
|
|
RETURNS TABLE(grid_location_x bigint, grid_location_y bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT t.grid_location_x, t.grid_location_y
|
|
FROM landclaim_segments AS t
|
|
WHERE t.totem_id = in_totem_id;
|
|
END; $function$
|
|
|
|
|
|
-- get_learned_building_sets(in_account_id bigint) -> SETOF text
|
|
-- oid: 58316 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_learned_building_sets(in_account_id bigint)
|
|
RETURNS SETOF text
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT UNNEST(learned_building_sets) FROM building_progression WHERE account_id = in_account_id;
|
|
END; $function$
|
|
|
|
|
|
-- get_learned_new_buildable_pieces(in_account_id bigint) -> SETOF text
|
|
-- oid: 58317 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_learned_new_buildable_pieces(in_account_id bigint)
|
|
RETURNS SETOF text
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT UNNEST(new_buildable_pieces) FROM building_progression WHERE account_id = in_account_id;
|
|
END; $function$
|
|
|
|
|
|
-- get_login_journey_nodes(in_account_id bigint) -> dune.journeynodeinfo[]
|
|
-- oid: 58318 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_login_journey_nodes(in_account_id bigint)
|
|
RETURNS dune.journeynodeinfo[]
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result JourneyNodeInfo[];
|
|
BEGIN
|
|
SELECT
|
|
array_agg(
|
|
(
|
|
res.story_node_id,
|
|
res.override_reward_block,
|
|
res.has_pending_reward,
|
|
res.complete_condition_state,
|
|
res.reveal_condition_state,
|
|
res.fail_condition_state,
|
|
res.metadata_state,
|
|
res.reset_group
|
|
)::JourneyNodeInfo
|
|
)
|
|
INTO result
|
|
FROM journey_story_node res
|
|
WHERE res.account_id = in_account_id;
|
|
|
|
RETURN result;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_login_journey_nodes_cooldown(in_account_id bigint) -> dune.journeynodecooldowninfo[]
|
|
-- oid: 58319 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_login_journey_nodes_cooldown(in_account_id bigint)
|
|
RETURNS dune.journeynodecooldowninfo[]
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result JourneyNodeCooldownInfo[];
|
|
BEGIN
|
|
SELECT
|
|
array_agg(
|
|
(
|
|
res.story_node_id,
|
|
res.time_to_expire
|
|
)::JourneyNodeCooldownInfo
|
|
)
|
|
INTO result
|
|
FROM journey_story_node_cooldown res
|
|
WHERE res.account_id = in_account_id;
|
|
|
|
RETURN result;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_mnemonic_recall_lessons(in_account_id bigint) -> TABLE(id bigint, lesson_id text, lession_state bigint, lesson_progress integer, is_new boolean)
|
|
-- oid: 58320 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_mnemonic_recall_lessons(in_account_id bigint)
|
|
RETURNS TABLE(id bigint, lesson_id text, lession_state bigint, lesson_progress integer, is_new boolean)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT t.id, t.lesson_id, t.lesson_state, t.lesson_progress, t.is_new
|
|
FROM mnemonic_recall as t
|
|
WHERE t.account_id = in_account_id
|
|
ORDER BY t.id;
|
|
END; $function$
|
|
|
|
|
|
-- get_online_player_controller_ids(in_map text) -> SETOF bigint
|
|
-- oid: 58321 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_online_player_controller_ids(in_map text)
|
|
RETURNS SETOF bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return query SELECT DISTINCT ps.player_controller_id
|
|
FROM player_state ps
|
|
JOIN actors a ON (a.id = ps.player_controller_id)
|
|
WHERE ps.online_status = 'Online' AND a.map = in_map;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- get_online_player_controller_ids_on_farm() -> SETOF bigint
|
|
-- oid: 58322 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_online_player_controller_ids_on_farm()
|
|
RETURNS SETOF bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return query SELECT DISTINCT ps.player_controller_id
|
|
FROM player_state ps
|
|
JOIN actors a ON (a.id = ps.player_controller_id)
|
|
WHERE ps.online_status = 'Online';
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- get_partition_presets() -> SETOF text
|
|
-- oid: 58323 kind: FUNCTION category: partition
|
|
-- comment: Adds a partition only if its unique. Not using constraints, as this is only a helper function.
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_partition_presets()
|
|
RETURNS SETOF text
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return query SELECT routine_name::text as preset_function FROM information_schema.routines WHERE routine_type = 'FUNCTION' and routine_name ilike 'initialize_partitions_%';
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- get_partitions(in_map text) -> SETOF bigint
|
|
-- oid: 58324 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_partitions(in_map text)
|
|
RETURNS SETOF bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
SELECT partition_id FROM world_partition where map = in_map order by partition_id ASC;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- get_party_members(in_party_id bigint) -> TABLE(player_id bigint, fls_id text, party_id bigint)
|
|
-- oid: 58325 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_party_members(in_party_id bigint)
|
|
RETURNS TABLE(player_id bigint, fls_id text, party_id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT pm.player_id, acc.user, pm.party_id
|
|
FROM party_members pm
|
|
LEFT JOIN player_state ps ON ps.player_controller_id = pm.player_id
|
|
LEFT JOIN accounts acc ON acc.id = ps.account_id
|
|
WHERE pm.party_id = in_party_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_permission_actors_for_server(in_server_info dune.serverinfo) -> SETOF dune.actorpermissioncombineddata
|
|
-- oid: 58326 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_permission_actors_for_server(in_server_info dune.serverinfo)
|
|
RETURNS SETOF dune.actorpermissioncombineddata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return query
|
|
with ids as (
|
|
select array_agg(actors.id) as ids
|
|
from permission_actor join actors on actors.id = permission_actor.actor_id
|
|
where server_info_match(actors, in_server_info) and actors.owner_account_id is null
|
|
)
|
|
select permissions.* from ids, get_permission_for_actors(ids.ids) as permissions;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_permission_for_actor(in_actor_id bigint) -> dune.actorpermissioncombineddata
|
|
-- oid: 58327 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_permission_for_actor(in_actor_id bigint)
|
|
RETURNS dune.actorpermissioncombineddata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return (select get_permission_for_actors(array[in_actor_id]) limit 1);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_permission_for_actors(in_actor_id bigint[]) -> SETOF dune.actorpermissioncombineddata
|
|
-- oid: 58328 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_permission_for_actors(in_actor_id bigint[])
|
|
RETURNS SETOF dune.actorpermissioncombineddata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT
|
|
-- ActorPermissionData
|
|
ROW(
|
|
ROW(
|
|
permission_actor.actor_id,
|
|
permission_actor.actor_name,
|
|
actors.class,
|
|
permission_actor.actor_type,
|
|
permission_actor.access_level,
|
|
permission_actor.is_child
|
|
)::ActorPermissionEntry,
|
|
array_agg(
|
|
ROW(
|
|
permission_actor_rank.rank,
|
|
permission_actor_rank.player_id
|
|
)::ActorPermissionRankData
|
|
) FILTER (WHERE permission_actor_rank.player_id IS NOT NULL),
|
|
array_agg(guild_members.guild_id) FILTER (WHERE permission_actor_rank.player_id IS NOT NULL)
|
|
)::ActorPermissionData AS data,
|
|
|
|
-- ActorPermissionLocationData
|
|
ROW(
|
|
actors.id,
|
|
actors.partition_id,
|
|
actors.map,
|
|
actors.dimension_index,
|
|
actors.transform
|
|
)::ActorPermissionLocationData AS loc
|
|
FROM
|
|
permission_actor
|
|
LEFT JOIN permission_actor_rank on permission_actor.actor_id = permission_actor_rank.permission_actor_id
|
|
LEFT JOIN guild_members ON guild_members.player_id = permission_actor_rank.player_id
|
|
LEFT JOIN actors ON actors.id = permission_actor.actor_id
|
|
WHERE
|
|
permission_actor.actor_id = ANY(in_actor_id)
|
|
GROUP BY
|
|
permission_actor.actor_id,
|
|
actors.id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_permission_for_player_actors(in_player_id bigint, in_min_rank smallint) -> SETOF dune.actorpermissioncombineddata
|
|
-- oid: 58329 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_permission_for_player_actors(in_player_id bigint, in_min_rank smallint)
|
|
RETURNS SETOF dune.actorpermissioncombineddata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
WITH player_owned_actors AS
|
|
(
|
|
SELECT array_agg(permission_actor_id) AS ids
|
|
FROM permission_actor_rank join actors on actors.id = permission_actor_rank.permission_actor_id
|
|
WHERE permission_actor_rank.player_id = in_player_id AND permission_actor_rank.rank <= in_min_rank and actors.owner_account_id is null
|
|
)
|
|
SELECT permissions.* FROM player_owned_actors, get_permission_for_actors(player_owned_actors.ids) AS permissions;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_placeable_id(in_actor_id bigint, in_class text, in_building_type text) -> dune.placeablegetidcomposite
|
|
-- oid: 58330 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_placeable_id(in_actor_id bigint, in_class text, in_building_type text)
|
|
RETURNS dune.placeablegetidcomposite
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
placeable_id BIGINT;
|
|
BEGIN
|
|
SELECT INTO placeable_id id FROM placeables WHERE "id" = in_actor_id;
|
|
|
|
IF placeable_id IS NULL THEN
|
|
SELECT assign_actor_id(in_class) id INTO placeable_id;
|
|
INSERT INTO placeables("id", "building_type") VALUES(placeable_id, in_building_type);
|
|
END IF;
|
|
|
|
return ROW(placeable_id)::PlaceableGetIdComposite;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_access_codes(in_account_id bigint) -> TABLE(access_code integer, access_code_type integer)
|
|
-- oid: 58331 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_access_codes(in_account_id bigint)
|
|
RETURNS TABLE(access_code integer, access_code_type integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT p.access_code, p.access_code_type
|
|
FROM player_access_codes AS p
|
|
WHERE p.account_id = in_account_id;
|
|
END; $function$
|
|
|
|
|
|
-- get_player_current_faction_reputation(in_actor_id bigint, OUT out_faction_id smallint, OUT out_reputation_amount integer) -> record
|
|
-- oid: 58332 kind: FUNCTION category: faction
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_current_faction_reputation(in_actor_id bigint, OUT out_faction_id smallint, OUT out_reputation_amount integer)
|
|
RETURNS record
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
SELECT
|
|
pf.faction_id,
|
|
COALESCE(pfr.reputation_amount, 0)
|
|
INTO out_faction_id, out_reputation_amount
|
|
FROM player_faction pf
|
|
LEFT JOIN player_faction_reputation pfr
|
|
ON pfr.actor_id = pf.actor_id AND pfr.faction_id = pf.faction_id
|
|
WHERE pf.actor_id = in_actor_id
|
|
limit 1;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_faction(in_player_id bigint, in_neutral_faction_id smallint) -> smallint
|
|
-- oid: 58333 kind: FUNCTION category: faction
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_faction(in_player_id bigint, in_neutral_faction_id smallint)
|
|
RETURNS smallint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
player_faction_id SMALLINT;
|
|
BEGIN
|
|
SELECT player_faction.faction_id INTO player_faction_id
|
|
FROM player_faction
|
|
WHERE actor_id = in_player_id;
|
|
|
|
IF player_faction_id IS NULL THEN
|
|
player_faction_id := in_neutral_faction_id;
|
|
END IF;
|
|
|
|
RETURN player_faction_id;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- get_player_faction_name(in_actor_id bigint, OUT player_faction_name text, OUT utc_time_faction_change timestamp without time zone) -> record
|
|
-- oid: 58334 kind: FUNCTION category: faction
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_faction_name(in_actor_id bigint, OUT player_faction_name text, OUT utc_time_faction_change timestamp without time zone)
|
|
RETURNS record
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
SELECT factions.name, player_faction.utc_time_faction_change AT TIME ZONE 'UTC' INTO player_faction_name, utc_time_faction_change
|
|
FROM factions INNER JOIN player_faction ON factions.id = player_faction.faction_id
|
|
WHERE player_faction.actor_id = in_actor_id
|
|
limit 1;
|
|
END; $function$
|
|
|
|
|
|
-- get_player_guild_invites(in_player_id bigint) -> TABLE(invite_id bigint, guild_id bigint, guild_name text, guild_description text, sender_player_id bigint, invite_sent_timespan bigint, character_name text, sender_character_name text)
|
|
-- oid: 58335 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_guild_invites(in_player_id bigint)
|
|
RETURNS TABLE(invite_id bigint, guild_id bigint, guild_name text, guild_description text, sender_player_id bigint, invite_sent_timespan bigint, character_name text, sender_character_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT guild_invites.invite_id, guilds.guild_id, guilds.guild_name, guilds.guild_description, guild_invites.sender_player_id, guild_invites.invite_sent_timespan, player_state.character_name, sender_player_state.character_name AS sender_character_name
|
|
FROM guild_invites
|
|
JOIN guilds ON guilds.guild_id = guild_invites.guild_id
|
|
JOIN player_state ON player_state.player_controller_id = guild_invites.player_id
|
|
JOIN player_state AS sender_player_state ON sender_player_state.player_controller_id = guild_invites.sender_player_id
|
|
WHERE player_id = in_player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_ids_online_state(in_player_ids bigint[]) -> SETOF dune.playeronlinestateentry
|
|
-- oid: 58336 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_ids_online_state(in_player_ids bigint[])
|
|
RETURNS SETOF dune.playeronlinestateentry
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT actors.id, player_state.character_name, (actors.map, actors.partition_id, actors.dimension_index)::ServerInfo, (player_state.last_avatar_activity AT TIME ZONE 'UTC')::TIMESTAMP, player_state.online_status
|
|
FROM actors
|
|
JOIN player_state ON player_state.player_controller_id = actors.id
|
|
WHERE actors.id = ANY(in_player_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_infos_for_actor_ids(in_actor_ids bigint[]) -> TABLE(player_id bigint, character_name text, fls_id text, funcom_id text, platform_id text, platform_name text)
|
|
-- oid: 58337 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_infos_for_actor_ids(in_actor_ids bigint[])
|
|
RETURNS TABLE(player_id bigint, character_name text, fls_id text, funcom_id text, platform_id text, platform_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT ps.player_controller_id, ps.character_name, acc.user, acc.funcom_id, acc.platform_id, acc.platform_name
|
|
FROM accounts acc LEFT JOIN player_state ps ON acc.id=ps.account_id
|
|
WHERE ps.player_controller_id = ANY(in_actor_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_infos_for_character_names(in_character_names text[]) -> TABLE(player_id bigint, character_name text, fls_id text, funcom_id text, platform_id text, platform_name text)
|
|
-- oid: 58338 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_infos_for_character_names(in_character_names text[])
|
|
RETURNS TABLE(player_id bigint, character_name text, fls_id text, funcom_id text, platform_id text, platform_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT ps.player_controller_id, ps.character_name, acc.user, acc.funcom_id, acc.platform_id, acc.platform_name
|
|
FROM accounts acc LEFT JOIN player_state ps ON acc.id=ps.account_id
|
|
WHERE ps.character_name = ANY(in_character_names);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_infos_for_fls_ids(in_fls_ids text[]) -> TABLE(player_id bigint, character_name text, fls_id text, funcom_id text, platform_id text, platform_name text)
|
|
-- oid: 58339 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_infos_for_fls_ids(in_fls_ids text[])
|
|
RETURNS TABLE(player_id bigint, character_name text, fls_id text, funcom_id text, platform_id text, platform_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT ps.player_controller_id, ps.character_name, acc.user, acc.funcom_id, acc.platform_id, acc.platform_name
|
|
FROM accounts acc LEFT JOIN player_state ps ON acc.id=ps.account_id
|
|
WHERE acc.user = ANY(in_fls_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_infos_for_funcom_ids(in_funcom_ids text[]) -> TABLE(player_id bigint, character_name text, fls_id text, funcom_id text, platform_id text, platform_name text)
|
|
-- oid: 58340 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_infos_for_funcom_ids(in_funcom_ids text[])
|
|
RETURNS TABLE(player_id bigint, character_name text, fls_id text, funcom_id text, platform_id text, platform_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT ps.player_controller_id, ps.character_name, acc.user, acc.funcom_id, acc.platform_id, acc.platform_name
|
|
FROM accounts acc LEFT JOIN player_state ps ON acc.id=ps.account_id
|
|
WHERE acc.funcom_id = ANY(in_funcom_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_online_state_within_grace_period_for_each_server() -> TABLE(fls_id text, previous_partition_id bigint, current_server_id text, online_status dune.playerconnectionstatus, within_grace_period boolean, last_disconnect timestamp without time zone, demo_playtime_seconds integer, logoff_persistence_end_time timestamp without time zone, party_id bigint)
|
|
-- oid: 58341 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_online_state_within_grace_period_for_each_server()
|
|
RETURNS TABLE(fls_id text, previous_partition_id bigint, current_server_id text, online_status dune.playerconnectionstatus, within_grace_period boolean, last_disconnect timestamp without time zone, demo_playtime_seconds integer, logoff_persistence_end_time timestamp without time zone, party_id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT accounts.user as fls_id, player_state.previous_server_partition_id as previous_partition_id, player_state.server_id as current_server_id, player_state.online_status as online_status, player_state.reconnect_grace_period_end > (now() AT TIME ZONE 'UTC')::TIMESTAMP as within_grace_period, (player_state.last_avatar_activity AT TIME ZONE 'UTC')::TIMESTAMP as last_disconnect, demo_users.demo_playtime_seconds, (player_state.logoff_persistence_end_time)::TIMESTAMP as logoff_persistence_end_time, party_members.party_id
|
|
FROM player_state
|
|
LEFT JOIN accounts ON accounts.id = player_state.account_id
|
|
LEFT JOIN demo_users ON accounts.user = demo_users.fls_id
|
|
LEFT JOIN party_members ON player_state.player_controller_id = party_members.player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_owned_vehicles_data(in_player_id bigint, in_account_id bigint) -> TABLE(out_actor_id bigint, out_name text, out_class text, out_map text, out_partition_id bigint, out_dimension integer, out_transform dune.transform, out_actor_state text)
|
|
-- oid: 58342 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_owned_vehicles_data(in_player_id bigint, in_account_id bigint)
|
|
RETURNS TABLE(out_actor_id bigint, out_name text, out_class text, out_map text, out_partition_id bigint, out_dimension integer, out_transform dune.transform, out_actor_state text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY WITH owned_actors AS(
|
|
SELECT (entry).actor_id, (entry).actor_name FROM get_permission_for_player_actors(in_player_id, 1::smallint) -- 1:owner
|
|
WHERE (entry).actor_type = 2 -- 2:vehicles
|
|
UNION SELECT vehicle_id, vehicle_name FROM recovered_vehicles -- note: recovered vehicles are removed from permission actors
|
|
WHERE account_id = in_account_id
|
|
) SELECT owned_actors.actor_id, actor_name, class, map, partition_id, dimension_index, transform, (actor_state).state::text
|
|
FROM owned_actors LEFT JOIN actors ON actors.id = owned_actors.actor_id LEFT JOIN actor_state ON actor_state.actor_id = owned_actors.actor_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_partition_id(in_fls_id text) -> bigint
|
|
-- oid: 58343 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_partition_id(in_fls_id text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
-- Only the player pawn actually travels and gets it's partition id updated
|
|
return (
|
|
select actors.partition_id
|
|
from accounts as acc
|
|
join player_state as ps on ps.account_id = acc.id
|
|
join actors on actors.id = ps.player_pawn_id
|
|
where acc.user = in_fls_id
|
|
);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_pawn(in_account_id bigint) -> TABLE(description dune.actordescription, server_info dune.serverinfo, player_tags text[])
|
|
-- oid: 58344 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_pawn(in_account_id bigint)
|
|
RETURNS TABLE(description dune.actordescription, server_info dune.serverinfo, player_tags text[])
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return query
|
|
with id as (select player_pawn_id as id from player_state where account_id = in_account_id limit 1),
|
|
tags as (select array_agg(tag) from player_tags where account_id = in_account_id)
|
|
select load_full_actors(array[id]) as description, get_actor_server_info(id) as server_info, (select * from tags) as player_tags
|
|
from id limit 1;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_player_virtual_currency_balances(in_controller_id bigint) -> TABLE(out_currency_id smallint, out_currency_balance bigint)
|
|
-- oid: 58345 kind: FUNCTION category: currency
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_player_virtual_currency_balances(in_controller_id bigint)
|
|
RETURNS TABLE(out_currency_id smallint, out_currency_balance bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return query (
|
|
with currencies as (select currency_id, balance from player_virtual_currency_balances where player_controller_id = in_controller_id),
|
|
bad_currencies as (select * from currencies where balance < 0),
|
|
target_account_id as (select account_id from player_state where player_controller_id = in_controller_id limit 1),
|
|
report_cheaters as (select currency_id, flag_player_as_cheater(target_account_id.account_id, 'negative_solaris') from bad_currencies, target_account_id),
|
|
fix_bad_currencies as (update player_virtual_currency_balances set balance = 0 from report_cheaters where player_controller_id = in_controller_id and player_virtual_currency_balances.currency_id = report_cheaters.currency_id)
|
|
select currency_id, balance from currencies
|
|
);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- get_players_demo_data(in_controller_ids bigint[]) -> SETOF dune.playerdemostatedescription
|
|
-- oid: 58346 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_players_demo_data(in_controller_ids bigint[])
|
|
RETURNS SETOF dune.playerdemostatedescription
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT ps.player_controller_id, (ps.last_avatar_activity AT TIME ZONE 'UTC')::TIMESTAMP, demo_playtime_seconds, demo_state
|
|
FROM encrypted_accounts acc
|
|
JOIN player_state ps ON ps.account_id = acc.id
|
|
JOIN demo_users du ON acc.user = du.fls_id
|
|
WHERE ps.player_controller_id = ANY (in_controller_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_recipes_to_remove(recipes_to_remove text[]) -> text[]
|
|
-- oid: 58347 kind: FUNCTION category: items_purge
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_recipes_to_remove(recipes_to_remove text[])
|
|
RETURNS text[]
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
declare
|
|
result text[];
|
|
begin
|
|
select array(
|
|
select unnest(recipes_to_remove)
|
|
except
|
|
select name
|
|
from removed_recipes
|
|
) into result;
|
|
return result;
|
|
end;
|
|
$function$
|
|
|
|
|
|
-- get_registered_spawned_actor(in_spawner_id bigint) -> SETOF bigint
|
|
-- oid: 58348 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_registered_spawned_actor(in_spawner_id bigint)
|
|
RETURNS SETOF bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT actor_id FROM actor_spawner_actors WHERE spawner_id = in_spawner_id;
|
|
END; $function$
|
|
|
|
|
|
-- get_respawn_locations(in_account_id bigint) -> dune.respawnlocation[]
|
|
-- oid: 58349 kind: FUNCTION category: spawner
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_respawn_locations(in_account_id bigint)
|
|
RETURNS dune.respawnlocation[]
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result RespawnLocation[];
|
|
BEGIN
|
|
SELECT
|
|
array_agg(
|
|
(res.id,
|
|
(
|
|
CASE
|
|
WHEN res.locator_transform IS NOT NULL THEN 'Transform'
|
|
WHEN res.locator_actor_id IS NOT NULL THEN 'PersistentActor'
|
|
WHEN res.locator_name IS NOT NULL THEN 'StaticLocatorName'
|
|
END::SpawnLocatorType,
|
|
res.locator_transform,
|
|
res.locator_actor_id,
|
|
res.locator_name,
|
|
res.locator_name_index
|
|
)::SpawnLocatorDescriptor,
|
|
res.map,
|
|
res.dimension,
|
|
res.last_used_timestamp,
|
|
res.group
|
|
)::RespawnLocation
|
|
)
|
|
INTO result
|
|
FROM player_respawn_locations res
|
|
WHERE res.account_id = in_account_id;
|
|
|
|
RETURN result;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_schema_version() -> integer
|
|
-- oid: 58350 kind: FUNCTION category: schema_meta
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_schema_version()
|
|
RETURNS integer
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return 999999;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- get_solaris_id() -> smallint
|
|
-- oid: 58351 kind: FUNCTION category: currency
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_solaris_id()
|
|
RETURNS smallint
|
|
LANGUAGE plpgsql
|
|
IMMUTABLE
|
|
AS $function$
|
|
DECLARE
|
|
solaris_id CONSTANT SMALLINT := 0;
|
|
BEGIN
|
|
return solaris_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_spawner_id(in_map text, in_name text, in_dimension_index integer) -> bigint
|
|
-- oid: 58352 kind: FUNCTION category: spawner
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_spawner_id(in_map text, in_name text, in_dimension_index integer)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
spawner_id BIGINT;
|
|
BEGIN
|
|
SELECT INTO spawner_id "id" FROM actor_spawners WHERE map = in_map AND name = in_name AND dimension_index = in_dimension_index;
|
|
IF spawner_id IS NULL THEN
|
|
INSERT INTO actor_spawners("map", "name", "dimension_index") VALUES(in_map, in_name, in_dimension_index) ON CONFLICT DO NOTHING RETURNING "id" INTO spawner_id;
|
|
IF spawner_id IS NULL THEN
|
|
SELECT INTO spawner_id "id" FROM actor_spawners WHERE map = in_map AND name = in_name AND dimension_index = in_dimension_index;
|
|
END IF;
|
|
END IF;
|
|
RETURN spawner_id;
|
|
END $function$
|
|
|
|
|
|
-- get_stored_user_data_encryption_key_hash() -> bytea
|
|
-- oid: 58353 kind: FUNCTION category: encryption
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_stored_user_data_encryption_key_hash()
|
|
RETURNS bytea
|
|
LANGUAGE sql
|
|
IMMUTABLE
|
|
AS $function$select null::bytea;$function$
|
|
|
|
|
|
-- get_stored_user_data_encryption_status() -> dune.userdataencryptionstatus
|
|
-- oid: 58354 kind: FUNCTION category: encryption
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_stored_user_data_encryption_status()
|
|
RETURNS dune.userdataencryptionstatus
|
|
LANGUAGE sql
|
|
IMMUTABLE
|
|
AS $function$select 'Disabled'::UserDataEncryptionStatus$function$
|
|
|
|
|
|
-- get_stored_user_data_encryption_taint_xmax() -> bigint
|
|
-- oid: 58355 kind: FUNCTION category: encryption
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_stored_user_data_encryption_taint_xmax()
|
|
RETURNS bigint
|
|
LANGUAGE sql
|
|
IMMUTABLE
|
|
AS $function$select null::int8;$function$
|
|
|
|
|
|
-- get_sub_inventory_id(in_owner_item_id bigint) -> bigint
|
|
-- oid: 58356 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_sub_inventory_id(in_owner_item_id bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
inv_id BIGINT;
|
|
BEGIN
|
|
SELECT INTO inv_id id FROM inventories WHERE item_id = in_owner_item_id;
|
|
IF inv_id IS NULL THEN
|
|
INSERT INTO inventories("id", "item_id") VALUES(DEFAULT, in_owner_item_id) RETURNING id INTO inv_id;
|
|
END IF;
|
|
RETURN inv_id;
|
|
END $function$
|
|
|
|
|
|
-- get_traveling_actor_id_and_types(in_actor_id bigint) -> TABLE(id bigint, is_instigator boolean, is_player boolean, level integer)
|
|
-- oid: 58357 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_traveling_actor_id_and_types(in_actor_id bigint)
|
|
RETURNS TABLE(id bigint, is_instigator boolean, is_player boolean, level integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
select t.id, t.is_instigator, (ps.player_pawn_id is not null) as is_player, t.level
|
|
from get_traveling_actor_ids(in_actor_id) as t
|
|
left join player_state as ps
|
|
on t.id = ps.player_pawn_id
|
|
order by t.level, t.id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- get_traveling_actor_ids(in_actor_id bigint, in_max_recursion_level integer) -> TABLE(id bigint, is_instigator boolean, level integer)
|
|
-- oid: 58358 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_traveling_actor_ids(in_actor_id bigint, in_max_recursion_level integer DEFAULT 5)
|
|
RETURNS TABLE(id bigint, is_instigator boolean, level integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
with recursive
|
|
-- go down the dependency tree and gather all the parents
|
|
p(id, lvl) AS (
|
|
select a.id, 0
|
|
from actors as a
|
|
where (in_actor_id = a.id)
|
|
union all
|
|
select ap.parent_id, (p.lvl - 1)
|
|
from p, travel_actor_parent as ap
|
|
where (p.id = ap.id) and (p.lvl > -in_max_recursion_level)
|
|
),
|
|
-- find the most distant parent (root)
|
|
r as (
|
|
select * from p order by p.lvl limit 1
|
|
),
|
|
-- go up the tree from the root and gather all the children
|
|
t(id, ins, lvl) as (
|
|
select r.id, true, 0 from r
|
|
union all
|
|
select ap.id, ap.is_instigator, (t.lvl + 1)
|
|
from t, travel_actor_parent as ap
|
|
where (t.id = ap.parent_id) and (t.lvl < 2 * in_max_recursion_level)
|
|
)
|
|
select * from t order by t.lvl, id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- get_traveling_actors_fls_ids(in_actor_id bigint) -> TABLE(out_id text)
|
|
-- oid: 58359 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_traveling_actors_fls_ids(in_actor_id bigint)
|
|
RETURNS TABLE(out_id text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
select a.user
|
|
from get_traveling_actor_ids(in_actor_id) as t
|
|
inner join player_state as ps
|
|
on t.id = ps.player_pawn_id
|
|
inner join accounts as a
|
|
on a.id = ps.account_id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- get_traveling_non_player_actor_ids(in_actor_id bigint) -> TABLE(id bigint)
|
|
-- oid: 58360 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_traveling_non_player_actor_ids(in_actor_id bigint)
|
|
RETURNS TABLE(id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
select t.id
|
|
from get_traveling_actor_ids(in_actor_id) as t
|
|
left join player_state as ps
|
|
on t.id = ps.player_pawn_id
|
|
left join travel_actor_parent as ap
|
|
on ap.id = in_actor_id
|
|
where
|
|
ps.player_pawn_id is null
|
|
and ap.is_instigator is true
|
|
order by t.level, t.id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- get_unbacked_up_vehicle_ids_for_account(in_account_id bigint) -> TABLE(vehicle_id bigint)
|
|
-- oid: 58361 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_unbacked_up_vehicle_ids_for_account(in_account_id bigint)
|
|
RETURNS TABLE(vehicle_id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT v.id
|
|
FROM vehicles v
|
|
JOIN permission_actor_rank par ON v.id = par.permission_actor_id
|
|
JOIN player_state ps ON par.player_id = ps.player_controller_id
|
|
left join backup_vehicles bv ON v.id = bv.vehicle_id
|
|
WHERE ps.account_id = in_account_id
|
|
AND bv.vehicle_id IS NULL;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_universe_time() -> TABLE(universe_time_timestamp timestamp without time zone, down_time_accumulation bigint)
|
|
-- oid: 58362 kind: FUNCTION category: schema_meta
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_universe_time()
|
|
RETURNS TABLE(universe_time_timestamp timestamp without time zone, down_time_accumulation bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT farm_variables.universe_time_timestamp, farm_variables.down_time_accumulation from farm_variables;
|
|
RETURN;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- get_vehicle_id(in_actor_id bigint, in_class text) -> bigint
|
|
-- oid: 58364 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_vehicle_id(in_actor_id bigint, in_class text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
vehicle_id BIGINT;
|
|
BEGIN
|
|
SELECT INTO vehicle_id id FROM vehicles WHERE "id" = in_actor_id;
|
|
IF vehicle_id IS NULL THEN
|
|
SELECT assign_actor_id(in_class) id INTO vehicle_id;
|
|
INSERT INTO vehicles("id") VALUES(vehicle_id);
|
|
END IF;
|
|
RETURN vehicle_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- get_vehicle_module_inventory_id(in_vehicle_module_id bigint, in_vehicle_module_inventory_type integer) -> bigint
|
|
-- oid: 58365 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.get_vehicle_module_inventory_id(in_vehicle_module_id bigint, in_vehicle_module_inventory_type integer)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
inv_id BIGINT;
|
|
BEGIN
|
|
SELECT INTO inv_id inventory_id FROM vehicle_module_inventories vi JOIN inventories i ON (vi.inventory_id = i.id) WHERE i.vehicle_module_id = in_vehicle_module_id AND vi.vehicle_module_inventory_type = in_vehicle_module_inventory_type;
|
|
IF inv_id IS NULL THEN
|
|
INSERT INTO inventories("id", "vehicle_module_id") VALUES(DEFAULT, in_vehicle_module_id) RETURNING id INTO inv_id;
|
|
INSERT INTO vehicle_module_inventories("inventory_id", "vehicle_module_inventory_type") VALUES(inv_id, in_vehicle_module_inventory_type);
|
|
END IF;
|
|
RETURN inv_id;
|
|
END $function$
|
|
|
|
|
|
-- guild_handle_actor_delete(in_player_id bigint) -> void
|
|
-- oid: 58366 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.guild_handle_actor_delete(in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_guild_id BIGINT;
|
|
out_new_leader_id BIGINT;
|
|
out_guild_count INT;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- remove invites
|
|
PERFORM reject_guild_invite(invite_id) FROM guild_invites
|
|
where player_id = in_player_id OR sender_player_id = in_player_id;
|
|
|
|
-- Get member guild id
|
|
SELECT guild_id INTO out_guild_id FROM guild_members WHERE player_id = in_player_id;
|
|
IF FOUND THEN
|
|
|
|
SELECT INTO out_guild_count COUNT(*) FROM guild_members WHERE guild_id = out_guild_id;
|
|
|
|
IF out_guild_count < 2 THEN
|
|
PERFORM disband_guild(out_guild_id);
|
|
ELSE
|
|
-- Promote new leder
|
|
IF is_player_guild_admin(in_player_id, out_guild_id) THEN
|
|
SELECT player_id into out_new_leader_id from guild_members
|
|
WHERE guild_id = out_guild_id AND player_id <> in_player_id
|
|
LIMIT 1;
|
|
IF out_new_leader_id IS NOT NULL THEN
|
|
PERFORM promote_guild_member(out_guild_id, out_new_leader_id, 100::smallint);
|
|
END IF;
|
|
END IF;
|
|
-- remove member
|
|
PERFORM remove_guild_members(ARRAY[in_player_id], out_guild_id, 0::smallint);
|
|
END IF;
|
|
END IF;
|
|
|
|
END
|
|
$function$
|
|
|
|
|
|
-- guilds_get_exclusive_operation_lock() -> void
|
|
-- oid: 58367 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.guilds_get_exclusive_operation_lock()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM pg_advisory_xact_lock(601145); -- GUILDS in leet :/
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- handle_player_faction_guild_effects(in_player_id bigint, in_faction_id smallint, neutral_faction_id smallint) -> void
|
|
-- oid: 58368 kind: FUNCTION category: faction
|
|
|
|
CREATE OR REPLACE FUNCTION dune.handle_player_faction_guild_effects(in_player_id bigint, in_faction_id smallint, neutral_faction_id smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
guild_member_record record;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
SELECT * INTO guild_member_record
|
|
FROM guild_members
|
|
JOIN guilds ON guilds.guild_id = guild_members.guild_id
|
|
WHERE player_id = in_player_id;
|
|
|
|
IF guild_member_record IS NOT NULL THEN
|
|
PERFORM pg_notify('guild_notify_channel', format('player_guild_data_changed#{"GuildId" : %s , "PlayerId" : %s, "FactionId" : %s}', guild_member_record.guild_id, in_player_id, in_faction_id));
|
|
IF guild_member_record.guild_faction != neutral_faction_id THEN
|
|
-- If guild leader changes faction and guild already has a non neutral faction, break the guild allegiance
|
|
IF is_player_guild_admin(in_player_id, guild_member_record.guild_id) THEN
|
|
PERFORM break_guild_allegiance(guild_member_record.guild_id, neutral_faction_id);
|
|
-- Neutral player changing to Faction A while Guild is Faction B must be kicked
|
|
ELSEIF guild_member_record.guild_faction != in_faction_id AND in_faction_id != neutral_faction_id THEN
|
|
PERFORM remove_guild_members(ARRAY[in_player_id], guild_member_record.guild_id, 2::smallint);
|
|
END IF;
|
|
END IF;
|
|
END IF;
|
|
PERFORM clean_guild_invites_with_incompatible_faction(in_player_id, in_faction_id, neutral_faction_id);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- igwo_delete_world_partitions(in_partition_ids bigint[]) -> void
|
|
-- oid: 58369 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_delete_world_partitions(in_partition_ids bigint[])
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
delete from world_partition where partition_id = any(in_partition_ids);
|
|
$function$
|
|
|
|
|
|
-- igwo_get_partition_id_seq_last_value() -> bigint
|
|
-- oid: 58370 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_get_partition_id_seq_last_value()
|
|
RETURNS bigint
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select last_value from world_partition_partition_id_seq;
|
|
$function$
|
|
|
|
|
|
-- igwo_get_partition_ids() -> SETOF bigint
|
|
-- oid: 58371 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_get_partition_ids()
|
|
RETURNS SETOF bigint
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select partition_id from world_partition order by partition_id asc;
|
|
$function$
|
|
|
|
|
|
-- igwo_get_partitions() -> TABLE(partition_id bigint, map text, dimension_index integer, label text, min_x double precision, min_y double precision, max_x double precision, max_y double precision)
|
|
-- oid: 58372 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_get_partitions()
|
|
RETURNS TABLE(partition_id bigint, map text, dimension_index integer, label text, min_x double precision, min_y double precision, max_x double precision, max_y double precision)
|
|
LANGUAGE sql
|
|
AS $function$
|
|
SELECT
|
|
partition_id,
|
|
map,
|
|
dimension_index,
|
|
label,
|
|
(partition_definition->'box'->>'min_x')::float8,
|
|
(partition_definition->'box'->>'min_y')::float8,
|
|
(partition_definition->'box'->>'max_x')::float8,
|
|
(partition_definition->'box'->>'max_y')::float8
|
|
FROM world_partition
|
|
ORDER BY partition_id ASC;
|
|
$function$
|
|
|
|
|
|
-- igwo_get_server_details() -> TABLE(address text, server_id text, ready boolean, partition_id bigint, map text, dimension_index integer, label text)
|
|
-- oid: 58373 kind: FUNCTION category: igwo
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_get_server_details()
|
|
RETURNS TABLE(address text, server_id text, ready boolean, partition_id bigint, map text, dimension_index integer, label text)
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select
|
|
host(fs.igw_addr)||':'||fs.igw_port as address,
|
|
fs.server_id,
|
|
fs.ready,
|
|
wp.partition_id,
|
|
wp.map,
|
|
wp.dimension_index,
|
|
wp.label
|
|
from get_farm_state() fs
|
|
left join world_partition wp on wp.server_id = fs.server_id
|
|
where fs.server_id is not null;
|
|
$function$
|
|
|
|
|
|
-- igwo_insert_world_partition(in_partition_id bigint, in_map text, in_partition_definition jsonb, in_dimension_index integer, in_partition_label text) -> bigint
|
|
-- oid: 58374 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_insert_world_partition(in_partition_id bigint, in_map text, in_partition_definition jsonb, in_dimension_index integer DEFAULT 0, in_partition_label text DEFAULT NULL::text)
|
|
RETURNS bigint
|
|
LANGUAGE sql
|
|
AS $function$
|
|
insert into world_partition(partition_id, map, partition_definition, dimension_index, label)
|
|
values (
|
|
in_partition_id,
|
|
in_map,
|
|
in_partition_definition,
|
|
in_dimension_index,
|
|
coalesce(in_partition_label, determine_partition_label(in_map, in_dimension_index, null, false, in_partition_id)))
|
|
returning partition_id;
|
|
$function$
|
|
|
|
|
|
-- igwo_next_partition_id_seq() -> bigint
|
|
-- oid: 58375 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_next_partition_id_seq()
|
|
RETURNS bigint
|
|
LANGUAGE sql
|
|
AS $function$
|
|
select nextval('world_partition_partition_id_seq');
|
|
$function$
|
|
|
|
|
|
-- igwo_notify_world_partition_update() -> void
|
|
-- oid: 58376 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_notify_world_partition_update()
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
notify world_partition_update;
|
|
$function$
|
|
|
|
|
|
-- igwo_restart_partition_id_seq(in_restart_with bigint) -> void
|
|
-- oid: 58377 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_restart_partition_id_seq(in_restart_with bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
-- Use execute to substitute the numeric parameter into the alter sequence command
|
|
execute format('alter sequence world_partition_partition_id_seq restart with %s', in_restart_with);
|
|
end;
|
|
$function$
|
|
|
|
|
|
-- igwo_update_world_partition(in_map text, in_partition_definition jsonb, in_partition_id bigint, in_dimension_index integer, in_label text) -> void
|
|
-- oid: 58378 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.igwo_update_world_partition(in_map text, in_partition_definition jsonb, in_partition_id bigint, in_dimension_index integer, in_label text DEFAULT NULL::text)
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
update world_partition
|
|
set map = in_map,
|
|
partition_definition = in_partition_definition,
|
|
dimension_index = in_dimension_index,
|
|
label = coalesce(in_label, label)
|
|
where partition_id = in_partition_id;
|
|
$function$
|
|
|
|
|
|
-- init_event_log(in_partition_id bigint) -> void
|
|
-- oid: 58379 kind: FUNCTION category: event_log
|
|
|
|
CREATE OR REPLACE FUNCTION dune.init_event_log(in_partition_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
threshold_ts TIMESTAMPTZ;
|
|
last_ts TIMESTAMPTZ;
|
|
cleanup_threshold_days CONSTANT INTEGER := 14;
|
|
BEGIN
|
|
-- calculate threshold
|
|
threshold_ts := now() - (cleanup_threshold_days * interval '1 day');
|
|
|
|
-- lock table
|
|
LOCK TABLE event_log_maintanence IN EXCLUSIVE MODE;
|
|
|
|
SELECT last_cleanup
|
|
INTO last_ts
|
|
FROM event_log_maintanence;
|
|
|
|
IF last_ts < threshold_ts THEN
|
|
-- delete events older then the passed in threshold
|
|
DELETE FROM event_log
|
|
WHERE event_time < threshold_ts;
|
|
|
|
-- Update last_cleanup in event_log_maintanence
|
|
UPDATE event_log_maintanence
|
|
SET last_cleanup = now();
|
|
END IF;
|
|
|
|
-- update partition_id
|
|
PERFORM set_config('dune.partition_id', in_partition_id::TEXT, false);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- initialize_partitions_basic_battlegroup() -> void
|
|
-- oid: 58380 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_partitions_basic_battlegroup()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('SH_HarkoVillage', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('SH_HarkoVillage', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('SH_Arrakeen', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('SH_Arrakeen', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('DeepDesert_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('DeepDesert_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('DeepDesert_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 2);
|
|
perform add_partition_unique('Overmap', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform update_partition_labels();
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- initialize_partitions_basic_survival_1() -> void
|
|
-- oid: 58381 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_partitions_basic_survival_1()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 2);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 3);
|
|
perform update_partition_labels();
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- initialize_partitions_development_battlegroup() -> void
|
|
-- oid: 58382 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_partitions_development_battlegroup()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
-- Current battlegroup maps
|
|
perform initialize_partitions_full_battlegroup();
|
|
|
|
-- Core development maps
|
|
perform initialize_partitions_editor_default_1x1();
|
|
perform initialize_partitions_igw_test_small_2x2();
|
|
perform initialize_partitions_igw_training();
|
|
|
|
-- Additional Gyms
|
|
perform add_partition_unique('CombatGym_01', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0, 'CombatGym_01');
|
|
perform add_partition_unique('Audio_Gym', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0, 'Audio_Gym');
|
|
perform add_partition_unique('CombatGym_Camps', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0, 'CombatGym_Camps');
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- initialize_partitions_editor_default_1x1() -> void
|
|
-- oid: 58383 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_partitions_editor_default_1x1()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
perform add_partition_unique('Editor_Default', '{"type": "box2d_array", "boxes": [{"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}]}', 0, 'Editor_Default');
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- initialize_partitions_full_battlegroup() -> void
|
|
-- oid: 58384 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_partitions_full_battlegroup()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 2);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 3);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 4);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 5);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 6);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 7);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 8);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 9);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 10);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 11);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 12);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 13);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 14);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 15);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 16);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 17);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 18);
|
|
perform add_partition_unique('Survival_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 19);
|
|
perform add_partition_unique('SH_HarkoVillage', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('SH_HarkoVillage', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('SH_Arrakeen', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('SH_Arrakeen', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('SH_FallenLight', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('SH_FallenLight', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('CB_Story_Hephaestus', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Story_Ecolab_Carthag', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Story_WaterFatManor', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('DeepDesert_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('DeepDesert_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('DeepDesert_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 2);
|
|
perform add_partition_unique('Overmap', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('Story_ProcesVerbal', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('DLC_Story_LostHarvest', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('DLC_Story_LostHarvest_EcolabA', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('DLC_Story_LostHarvest_EcolabB', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('DLC_Story_LostHarvest_ForgottenLab', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('Story_ArtOfKanly', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('Story_HeighlinerDungeon', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Dungeon_Hephaestus', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Dungeon_OldCarthag', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Story_BanditFortress01', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Overland_S_05', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Overland_S_06', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Overland_S_04', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Overland_M_01', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Overland_S_07', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('Story_Faction_Outpost_Hark', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('Story_Faction_Outpost_Atre', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Ecolab_Bronze_Green_089', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Ecolab_Bronze_Green_152', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Ecolab_Bronze_Green_195', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Ecolab_Bronze_Green_024', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Ecolab_Bronze_Green_136', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('PolarCap_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('PolarCap_1', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 1);
|
|
perform add_partition_unique('CB_Story_DestroyedZanovar', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Story_OrbitalMonitor', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Dungeon_TheFacility', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Dungeon_ThePit', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform add_partition_unique('CB_Overland_S_08', '{"box": {"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0}, "type": "box2d_array"}', 0);
|
|
perform update_partition_labels();
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- initialize_partitions_igw_test_small_2x1() -> void
|
|
-- oid: 58385 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_partitions_igw_test_small_2x1()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
perform add_partition_unique('IGW_Test_Small', '{"type": "box2d_array", "boxes": [{"max_x": 0.5, "max_y": 1, "min_x": 0, "min_y": 0}]}', 0, 'IGW_Test_Small_A1');
|
|
perform add_partition_unique('IGW_Test_Small', '{"type": "box2d_array", "boxes": [{"max_x": 1, "max_y": 1, "min_x": 0.5, "min_y": 0}]}', 0, 'IGW_Test_Small_A2');
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- initialize_partitions_igw_test_small_2x2() -> void
|
|
-- oid: 58386 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_partitions_igw_test_small_2x2()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
perform add_partition_unique('IGW_Test_Small', '{"type": "box2d_array", "boxes": [{"max_x": 0.5, "max_y": 0.5, "min_x": 0, "min_y": 0}]}', 0, 'IGW_Test_Small_A1');
|
|
perform add_partition_unique('IGW_Test_Small', '{"type": "box2d_array", "boxes": [{"max_x": 0.5, "max_y": 1, "min_x": 0, "min_y": 0.5}]}', 0, 'IGW_Test_Small_A2');
|
|
perform add_partition_unique('IGW_Test_Small', '{"type": "box2d_array", "boxes": [{"max_x": 1, "max_y": 0.5, "min_x": 0.5, "min_y": 0}]}', 0, 'IGW_Test_Small_B1');
|
|
perform add_partition_unique('IGW_Test_Small', '{"type": "box2d_array", "boxes": [{"max_x": 1, "max_y": 1, "min_x": 0.5, "min_y": 0.5}]}', 0, 'IGW_Test_Small_B2');
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- initialize_partitions_igw_training() -> void
|
|
-- oid: 58387 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_partitions_igw_training()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
perform add_partition_unique('IGW_Training', '{"type": "box2d_array", "boxes": [{"max_x": 1, "max_y": 0.33333, "min_x": 0, "min_y": 0}]}', 0, 'IGW_Training_A1');
|
|
perform add_partition_unique('IGW_Training', '{"type": "box2d_array", "boxes": [{"max_x": 1, "max_y": 0.66667, "min_x": 0, "min_y": 0.33333}]}', 0, 'IGW_Training_A2');
|
|
perform add_partition_unique('IGW_Training', '{"type": "box2d_array", "boxes": [{"max_x": 1, "max_y": 1, "min_x": 0, "min_y": 0.66667}]}', 0, 'IGW_Training_A3');
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- initialize_specialization_keystones(in_keystones text[]) -> TABLE(keystone_id smallint, keystone_name text)
|
|
-- oid: 58388 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_specialization_keystones(in_keystones text[])
|
|
RETURNS TABLE(keystone_id smallint, keystone_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
LOCK TABLE specialization_keystones_map IN SHARE ROW EXCLUSIVE MODE;
|
|
|
|
-- Note: we filter the existing values before the insert, otherwise it bumps the generated id in specialization_keystones_map
|
|
INSERT INTO specialization_keystones_map (name)
|
|
SELECT in_keystone_name FROM UNNEST(in_keystones) in_keystone_name LEFT JOIN specialization_keystones_map k ON in_keystone_name = k.name
|
|
WHERE name IS NULL;
|
|
RETURN QUERY SELECT * from specialization_keystones_map;
|
|
END $function$
|
|
|
|
|
|
-- initialize_world_partition(in_map_name text, in_num_servers integer, in_dimension_index integer) -> SETOF bigint
|
|
-- oid: 58389 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.initialize_world_partition(in_map_name text, in_num_servers integer, in_dimension_index integer DEFAULT 0)
|
|
RETURNS SETOF bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
return query
|
|
with _cleanup as (
|
|
DELETE FROM world_partition WHERE map = in_map_name and dimension_index = in_dimension_index
|
|
)
|
|
INSERT INTO world_partition (map, partition_definition, dimension_index, label)
|
|
select in_map_name, format('{"type": "cell_index", "index": %s}', generate_series)::JSONB, in_dimension_index, in_map_name || '_' || in_dimension_index || '_' || generate_series
|
|
from generate_series(0, in_num_servers - 1)
|
|
returning partition_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- interact_get_vendor_items_bought_from_player(in_vendor_id text, in_player_id bigint, in_current_cycle_start_timestamp bigint) -> TABLE(out_template_id text, out_amount_bought integer)
|
|
-- oid: 58390 kind: FUNCTION category: stock_vendor
|
|
|
|
CREATE OR REPLACE FUNCTION dune.interact_get_vendor_items_bought_from_player(in_vendor_id text, in_player_id bigint, in_current_cycle_start_timestamp bigint)
|
|
RETURNS TABLE(out_template_id text, out_amount_bought integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
player_timestamp BIGINT;
|
|
BEGIN
|
|
-- Clean items bought by player if the vendor's cycle was reset since the last time they interacted with it
|
|
IF EXISTS
|
|
(SELECT * FROM vendor_stock_cycle
|
|
WHERE vendor_id = in_vendor_id AND player_id = in_player_id AND last_interacted_timestamp < in_current_cycle_start_timestamp)
|
|
THEN
|
|
DELETE FROM vendor_stock_state WHERE vendor_id = in_vendor_id AND player_id = in_player_id;
|
|
END IF;
|
|
|
|
PERFORM update_vendor_timestamp_for_player(in_vendor_id, in_player_id, in_current_cycle_start_timestamp);
|
|
|
|
RETURN QUERY
|
|
SELECT template_id, amount_bought FROM vendor_stock_state WHERE vendor_id = in_vendor_id AND player_id = in_player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- internal_add_party_member(in_invite_id bigint, in_party_id bigint, in_player_id bigint, in_platform_session_id text, in_platform_name text, in_max_party_member_count integer) -> dune.partyacceptinviteresult
|
|
-- oid: 58391 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.internal_add_party_member(in_invite_id bigint, in_party_id bigint, in_player_id bigint, in_platform_session_id text, in_platform_name text, in_max_party_member_count integer)
|
|
RETURNS dune.partyacceptinviteresult
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
party_exists BOOLEAN;
|
|
member_count INTEGER;
|
|
out_platform_members_count INTEGER;
|
|
out_player_name TEXT;
|
|
out_accept_error PartyAcceptInviteResult DEFAULT 'Success'::PartyAcceptInviteResult;
|
|
BEGIN
|
|
|
|
-- check if party exists
|
|
SELECT INTO party_exists EXISTS (SELECT 1 FROM parties WHERE party_id = in_party_id);
|
|
IF NOT party_exists THEN
|
|
PERFORM remove_party_invite(in_invite_id, 2::smallint); -- PartyNoLongerExists = 2
|
|
RAISE NOTICE 'Trying to add player % to non existing party %.', in_player_id, in_party_id;
|
|
out_accept_error = 'NonExistingParty'::PartyAcceptInviteResult;
|
|
RETURN out_accept_error;
|
|
END IF;
|
|
|
|
-- check party member count
|
|
SELECT INTO member_count COUNT(*) FROM party_members WHERE party_id = in_party_id;
|
|
IF member_count >= in_max_party_member_count THEN
|
|
PERFORM remove_party_invite(in_invite_id, 1::smallint); -- PartyFull = 1
|
|
RAISE NOTICE 'Trying to add more members than the allowed % to party %.', in_max_party_member_count, in_party_id;
|
|
out_accept_error = 'PartyFull'::PartyAcceptInviteResult;
|
|
RETURN out_accept_error;
|
|
END IF;
|
|
|
|
-- insert member
|
|
INSERT INTO party_members("player_id", "party_id") VALUES(in_player_id, in_party_id);
|
|
|
|
-- track platform information
|
|
SELECT num_of_players INTO out_platform_members_count FROM platform_parties_mapping WHERE platform_name = in_platform_name AND dune_party_id = in_party_id;
|
|
IF out_platform_members_count IS NOT NULL THEN
|
|
-- there was a platform session for the player's party
|
|
UPDATE platform_parties_mapping SET num_of_players = out_platform_members_count+1 WHERE platform_name = in_platform_name AND dune_party_id = in_party_id;
|
|
ELSE
|
|
-- no mapping for this platform yet, add
|
|
INSERT INTO platform_parties_mapping ("platform_session_id", "platform_name", "dune_party_id", "num_of_players")
|
|
SELECT in_platform_session_id, in_platform_name, in_party_id, 1
|
|
WHERE in_platform_session_id <> '' AND in_platform_name <> '';
|
|
END IF;
|
|
|
|
-- Get player name
|
|
SELECT player_state.character_name INTO out_player_name
|
|
FROM player_state WHERE player_state.player_controller_id = in_player_id;
|
|
|
|
PERFORM remove_party_invite(in_invite_id, 0::smallint); -- Silent = 0
|
|
|
|
PERFORM pg_notify('party_notify_channel', format(
|
|
'add_party_member#{"PartyId" : %s, "PlayerId" : %s, "PlayerName" : "%s", "PlayerPlatformName" : "%s", "PlayerPlatformSessionId" : "%s"}',
|
|
in_party_id, in_player_id, out_player_name, in_platform_name, in_platform_session_id));
|
|
|
|
RETURN out_accept_error;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- internal_create_party(in_invite_id bigint, in_leader_id bigint, in_leader_platform_session_id text, in_leader_platform_name text, in_member_id bigint, in_platform_session_id text, in_platform_name text) -> bigint
|
|
-- oid: 58392 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.internal_create_party(in_invite_id bigint, in_leader_id bigint, in_leader_platform_session_id text, in_leader_platform_name text, in_member_id bigint, in_platform_session_id text, in_platform_name text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
leader_registered BOOLEAN;
|
|
players_belong_to_party BOOLEAN;
|
|
out_party_id BIGINT;
|
|
out_player_name TEXT;
|
|
out_leader_name TEXT;
|
|
BEGIN
|
|
|
|
-- Check if the leader already exists in the parties table
|
|
SELECT INTO leader_registered EXISTS (SELECT 1 FROM parties WHERE party_leader_id = in_leader_id);
|
|
IF leader_registered THEN
|
|
RAISE EXCEPTION 'Leader already has a party.';
|
|
END IF;
|
|
|
|
-- Check if either the leader or member already exists in the party_members table
|
|
SELECT INTO players_belong_to_party EXISTS (SELECT 1 FROM party_members WHERE player_id = in_leader_id OR player_id = in_member_id);
|
|
IF players_belong_to_party THEN
|
|
RAISE EXCEPTION 'One of the players is already in a party.';
|
|
END IF;
|
|
|
|
-- If neither condition is met, insert the new party and members
|
|
INSERT INTO parties ("party_leader_id") VALUES (in_leader_id) RETURNING party_id INTO out_party_id;
|
|
INSERT INTO party_members (player_id, party_id) VALUES (in_leader_id, out_party_id), (in_member_id, out_party_id);
|
|
|
|
-- Update all of the leaders invites to have the new party as party id
|
|
UPDATE party_invites SET party_id = out_party_id WHERE sender_player_id = in_leader_id;
|
|
|
|
-- Get leader name
|
|
SELECT player_state.character_name INTO out_leader_name
|
|
FROM player_state WHERE player_state.player_controller_id = in_leader_id;
|
|
|
|
-- Get member name
|
|
SELECT player_state.character_name INTO out_player_name
|
|
FROM player_state WHERE player_state.player_controller_id = in_member_id;
|
|
|
|
-- Handle platform sessions mapping for new party
|
|
IF in_leader_platform_name = in_platform_name THEN
|
|
-- If players are from the same platform and leader has session id (console), we create mapping (if their platform_name and session_id are valid)
|
|
INSERT INTO platform_parties_mapping ("platform_session_id", "platform_name", "dune_party_id", "num_of_players")
|
|
SELECT in_leader_platform_session_id, in_leader_platform_name, out_party_id, 2
|
|
WHERE in_leader_platform_session_id <> '' AND in_leader_platform_name <> '';
|
|
ELSE
|
|
-- Create leader's platform session mapping if their platform_name and session_id are valid
|
|
INSERT INTO platform_parties_mapping ("platform_session_id", "platform_name", "dune_party_id", "num_of_players")
|
|
SELECT in_leader_platform_session_id, in_leader_platform_name, out_party_id, 1
|
|
WHERE in_leader_platform_session_id <> '' AND in_leader_platform_name <> '';
|
|
|
|
-- Create member's platform session mapping if their platform_name and session_id are valid
|
|
INSERT INTO platform_parties_mapping ("platform_session_id", "platform_name", "dune_party_id", "num_of_players")
|
|
SELECT in_platform_session_id, in_platform_name, out_party_id, 1
|
|
WHERE in_platform_session_id <> '' AND in_platform_name <> '';
|
|
END IF;
|
|
|
|
PERFORM remove_party_invite(in_invite_id, 0::smallint); -- Silent = 0
|
|
|
|
PERFORM pg_notify('party_notify_channel', format(
|
|
'create_party#{"PartyId" : %s, "LeaderId" : %s, "LeaderName" : "%s", "LeaderPlatformName" : "%s", "LeaderPlatformSessionId" : "%s", "MemberId" : %s, "MemberName" : "%s", "MemberPlatformName" : "%s", "MemberPlatformSessionId" : "%s"}',
|
|
out_party_id, in_leader_id, out_leader_name, in_leader_platform_name, in_leader_platform_session_id, in_member_id, out_player_name, in_platform_name, in_platform_session_id));
|
|
|
|
RETURN out_party_id;
|
|
|
|
END
|
|
$function$
|
|
|
|
|
|
-- is_player_guild_admin(in_player_id bigint, in_guild_id bigint) -> boolean
|
|
-- oid: 58393 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.is_player_guild_admin(in_player_id bigint, in_guild_id bigint)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_role_id SMALLINT;
|
|
BEGIN
|
|
SELECT role_id FROM guild_members WHERE player_id = in_player_id AND guild_id = in_guild_id INTO found_role_id;
|
|
IF NOT FOUND THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
RETURN found_role_id = 100;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- is_player_offline(in_fls_id text) -> boolean
|
|
-- oid: 58394 kind: FUNCTION category: lookup
|
|
-- comment: Return true if player is marked as offline, taking into account server crashing before players online state was updated in DB.
|
|
|
|
CREATE OR REPLACE FUNCTION dune.is_player_offline(in_fls_id text)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
declare
|
|
has_state int;
|
|
is_offline boolean;
|
|
begin
|
|
-- If there's no player_state row for this account, treat the player as offline
|
|
select count(*) into has_state
|
|
from player_state ps
|
|
join accounts a on a.id = ps.account_id
|
|
where a.user = in_fls_id;
|
|
|
|
if has_state = 0 then
|
|
return true;
|
|
end if;
|
|
|
|
select exists(
|
|
select 1
|
|
from player_state ps
|
|
join accounts a on a.id = ps.account_id
|
|
where a.user = in_fls_id
|
|
and (
|
|
ps.online_status = 'Offline'
|
|
-- Player is treated as offline if last played server is offline/unavailable, or not set at all
|
|
or (ps.server_id is null or ps.server_id not in (select * from active_server_ids))
|
|
)
|
|
) into is_offline;
|
|
|
|
return is_offline;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- is_player_party_leader(in_player_id bigint, in_party_id bigint) -> boolean
|
|
-- oid: 58395 kind: FUNCTION category: lookup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.is_player_party_leader(in_player_id bigint, in_party_id bigint)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_leader_id SMALLINT;
|
|
BEGIN
|
|
SELECT party_leader_id FROM parties WHERE party_id = in_party_id INTO found_leader_id;
|
|
IF NOT FOUND THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
RETURN found_leader_id = in_player_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- join_platform_session_party(in_leader_platform_id text, in_player_platform_id text, in_platform_session_id text, in_platform_name text, in_max_party_member_count integer) -> dune.partyacceptinviteresult
|
|
-- oid: 58396 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.join_platform_session_party(in_leader_platform_id text, in_player_platform_id text, in_platform_session_id text, in_platform_name text, in_max_party_member_count integer)
|
|
RETURNS dune.partyacceptinviteresult
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_party_id BIGINT;
|
|
out_accept_error PartyAcceptInviteResult DEFAULT 'Success'::PartyAcceptInviteResult;
|
|
out_leader_id BIGINT;
|
|
out_player_id BIGINT;
|
|
BEGIN
|
|
IF in_platform_name IS NULL OR length(in_platform_name) = 0 THEN
|
|
RAISE EXCEPTION 'platform_name must not be empty';
|
|
END IF;
|
|
IF in_platform_session_id IS NULL OR length(in_platform_session_id) = 0 THEN
|
|
RAISE EXCEPTION 'platform_session_id must not be empty';
|
|
END IF;
|
|
|
|
-- Fetch party id, but do nothing with it
|
|
SELECT dune_party_id INTO out_party_id
|
|
FROM platform_parties_mapping
|
|
WHERE platform_session_id = in_platform_session_id
|
|
AND platform_name = in_platform_name
|
|
LIMIT 1;
|
|
|
|
out_leader_id = get_controller_id_from_platform_id(in_leader_platform_id);
|
|
out_player_id = get_controller_id_from_platform_id(in_player_platform_id);
|
|
|
|
IF out_party_id IS NULL THEN
|
|
-- Using same platform name and platform session id cause they are joining through system invite, they'll always be the same platform.
|
|
PERFORM internal_create_party(NULL, out_leader_id, in_platform_session_id, in_platform_name,
|
|
out_player_id, in_platform_session_id, in_platform_name);
|
|
ELSE
|
|
out_accept_error := internal_add_party_member(NULL, out_party_id, out_player_id, in_platform_session_id, in_platform_name, in_max_party_member_count);
|
|
END IF;
|
|
|
|
RETURN out_accept_error;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- journey_story_node_cooldown_add(in_account_id bigint, in_story_node_id text, in_time_to_expire timestamp without time zone) -> void
|
|
-- oid: 58397 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.journey_story_node_cooldown_add(in_account_id bigint, in_story_node_id text, in_time_to_expire timestamp without time zone)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO journey_story_node_cooldown(account_id, story_node_id, time_to_expire)
|
|
VALUES(in_account_id, in_story_node_id, in_time_to_expire);
|
|
END $function$
|
|
|
|
|
|
-- journey_story_node_cooldown_delete_expired(in_time_to_check timestamp without time zone) -> void
|
|
-- oid: 58398 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.journey_story_node_cooldown_delete_expired(in_time_to_check timestamp without time zone)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM journey_story_node_cooldown WHERE time_to_expire < in_time_to_check;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_cast_vote(in_term_id bigint, in_player_id bigint, in_decree_name text) -> void
|
|
-- oid: 58399 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_cast_vote(in_term_id bigint, in_player_id bigint, in_decree_name text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
term_winning_faction_id SMALLINT = NULL;
|
|
elected_decree_id BIGINT = NULL;
|
|
player_guild_id BIGINT = NULL;
|
|
guild_faction_id SMALLINT = NULL;
|
|
voting_decree_id BIGINT = NULL;
|
|
voting_influence INTEGER = 0;
|
|
guild_ids_json JSON = NULL;
|
|
BEGIN
|
|
LOCK TABLE landsraad_decree_votes IN EXCLUSIVE MODE;
|
|
|
|
SELECT term.winning_faction_id, term.elected_decree_id FROM landsraad_decree_term AS term WHERE term.term_id = in_term_id INTO term_winning_faction_id, elected_decree_id;
|
|
|
|
IF term_winning_faction_id IS NULL THEN
|
|
RAISE EXCEPTION 'Cannot insert landsraad vote, term % has no winning faction yet', in_term_id;
|
|
END IF;
|
|
|
|
IF elected_decree_id IS NOT NULL THEN
|
|
RAISE EXCEPTION 'Cannot insert landsraad vote, term % already has an elected decree', in_term_id;
|
|
END IF;
|
|
|
|
SELECT guilds.guild_id, guilds.guild_faction FROM guild_members
|
|
JOIN guilds ON guild_members.guild_id = guilds.guild_id WHERE guild_members.player_id = in_player_id INTO player_guild_id, guild_faction_id;
|
|
|
|
IF player_guild_id IS NULL THEN
|
|
RAISE EXCEPTION 'Cannot insert landsraad vote, player % not in guild', in_player_id;
|
|
END IF;
|
|
|
|
IF guild_faction_id != term_winning_faction_id THEN
|
|
RAISE EXCEPTION 'Cannot insert landsraad vote, guild % not alligned to winning faction %', player_guild_id, term_winning_faction_id;
|
|
END IF;
|
|
|
|
IF is_player_guild_admin(in_player_id, player_guild_id) = FALSE THEN
|
|
RAISE EXCEPTION 'Cannot insert landsraad vote, player % is not guild admin of guild %', in_player_id, player_guild_id;
|
|
END IF;
|
|
|
|
IF EXISTS (SELECT FROM landsraad_decree_votes AS votes WHERE votes.guild_id = player_guild_id) THEN
|
|
RAISE WARNING 'Cannot insert landsraad vote, guild % has voted already', player_guild_id;
|
|
RETURN;
|
|
END IF;
|
|
|
|
SELECT decrees.id FROM landsraad_decree_rotation AS rotation
|
|
INNER JOIN landsraad_decrees AS decrees ON rotation.decree_id = decrees.id
|
|
WHERE decrees.decree_name = in_decree_name INTO voting_decree_id;
|
|
|
|
IF voting_decree_id IS NULL THEN
|
|
RAISE EXCEPTION 'Cannot insert landsraad vote, decree % not for election', in_decree_name;
|
|
END IF;
|
|
|
|
SELECT FLOOR(landsraad_load_guild_contribution(in_term_id, player_guild_id, term_winning_faction_id))::INTEGER INTO voting_influence;
|
|
|
|
IF voting_influence IS NULL THEN
|
|
RAISE WARNING 'Cannot insert landsraad vote, guild % has no contribution', player_guild_id;
|
|
RETURN;
|
|
END IF;
|
|
|
|
INSERT INTO landsraad_decree_votes VALUES(voting_decree_id, player_guild_id, in_player_id, voting_influence);
|
|
|
|
SELECT json_agg(player_guild_id) INTO guild_ids_json;
|
|
PERFORM pg_notify('landsraad_notify_channel', format('guild_vote_changed#{"GuildIds": %s}', guild_ids_json));
|
|
|
|
END $function$
|
|
|
|
|
|
-- landsraad_change_term_end_time(end_term_id bigint, new_end_time timestamp without time zone, in_test_term boolean) -> void
|
|
-- oid: 58400 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_change_term_end_time(end_term_id bigint, new_end_time timestamp without time zone, in_test_term boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
LOCK TABLE landsraad_decree_term IN EXCLUSIVE MODE;
|
|
UPDATE landsraad_decree_term SET test_term = in_test_term WHERE term_id = end_term_id AND test_term = false;
|
|
UPDATE landsraad_decree_term SET end_time = new_end_time AT TIME ZONE 'UTC' WHERE term_id = end_term_id;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_check_task_completion() -> trigger
|
|
-- oid: 58401 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_check_task_completion()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
task_completed BOOLEAN = FALSE;
|
|
BEGIN
|
|
-- if a faction reached the tasks's goal amount set the task as completed
|
|
WITH faction_progress AS (SELECT landsraad_task_faction_contributions.task_id, SUM(landsraad_task_faction_contributions.amount) AS amount FROM landsraad_task_faction_contributions
|
|
WHERE landsraad_task_faction_contributions.task_id = NEW.task_id AND faction_id = NEW.faction_id GROUP BY faction_id, landsraad_task_faction_contributions.task_id)
|
|
SELECT COALESCE (faction_progress.amount, 0) >= landsraad_tasks.goal_amount
|
|
FROM landsraad_tasks LEFT JOIN faction_progress ON landsraad_tasks.id = faction_progress.task_id
|
|
WHERE landsraad_tasks.id = NEW.task_id
|
|
INTO task_completed;
|
|
|
|
IF task_completed THEN
|
|
UPDATE landsraad_tasks SET completed = TRUE, winning_faction_id = NEW.faction_id, completion_time = NOW() WHERE id = NEW.task_id AND completed = FALSE;
|
|
PERFORM pg_notify('landsraad_notify_channel', 'state_changed');
|
|
END IF;
|
|
|
|
RETURN NULL;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_check_term_won() -> trigger
|
|
-- oid: 58402 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_check_term_won()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
row_completed BIGINT[] = NULL;
|
|
column_completed BIGINT[] = NULL;
|
|
diagonal_1_completed BIGINT[] = NULL;
|
|
diagonal_2_completed BIGINT[] = NULL;
|
|
sysselraad_amount INTEGER = 0;
|
|
BEGIN
|
|
-- check for sysselrad rule (a row, a column or a diagonal completed by a faction)
|
|
WITH board AS (SELECT task.id as task_id, task.winning_faction_id, task.board_index / 5 AS row, task.board_index % 5 AS col, task.sysselraad FROM landsraad_tasks task WHERE task.term_id = NEW.term_id)
|
|
SELECT
|
|
(SELECT array_agg(board.task_id) FROM board WHERE board.row = ANY(SELECT board.row FROM board WHERE board.winning_faction_id = NEW.winning_faction_id GROUP BY (board.row) HAVING COUNT(board.col) = 5)),
|
|
(SELECT array_agg(board.task_id) FROM board WHERE board.col = ANY(SELECT board.col FROM board WHERE board.winning_faction_id = NEW.winning_faction_id GROUP BY (board.col) HAVING COUNT(board.row) = 5)),
|
|
(SELECT CASE WHEN COUNT(board.winning_faction_id) = 5 THEN array_agg(board.task_id) END FROM ( VALUES (0, 0), (1, 1), (2, 2), (3, 3), (4, 4) ) AS t(row, col) JOIN board ON board.row = t.row AND board.col = t.col WHERE board.winning_faction_id = NEW.winning_faction_id),
|
|
(SELECT CASE WHEN COUNT(board.winning_faction_id) = 5 THEN array_agg(board.task_id) END FROM ( VALUES (0, 4), (1, 3), (2, 2), (3, 1), (4, 0) ) AS t(row, col) JOIN board ON board.row = t.row AND board.col = t.col WHERE board.winning_faction_id = NEW.winning_faction_id),
|
|
(SELECT COUNT(*) FROM board WHERE board.sysselraad)
|
|
INTO row_completed, column_completed, diagonal_1_completed, diagonal_2_completed, sysselraad_amount;
|
|
|
|
IF sysselraad_amount = 0 AND (row_completed IS NOT NULL OR column_completed IS NOT NULL OR diagonal_1_completed IS NOT NULL OR diagonal_2_completed IS NOT NULL) THEN
|
|
UPDATE landsraad_tasks SET sysselraad = TRUE WHERE id = ANY(row_completed || column_completed || diagonal_1_completed || diagonal_2_completed);
|
|
UPDATE landsraad_decree_term SET winning_faction_id = NEW.winning_faction_id WHERE term_id = NEW.term_id AND winning_faction_id IS NULL;
|
|
PERFORM pg_notify('landsraad_notify_channel', 'state_changed');
|
|
END IF;
|
|
|
|
RETURN NULL;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_collect_task_telemetry_for_faction(in_term_id bigint, in_faction_name text) -> TABLE(task_telemetry dune.landsraadtermtasktelemetry[])
|
|
-- oid: 58403 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_collect_task_telemetry_for_faction(in_term_id bigint, in_faction_name text)
|
|
RETURNS TABLE(task_telemetry dune.landsraadtermtasktelemetry[])
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
current_faction_id SMALLINT = NULL;
|
|
BEGIN
|
|
SELECT id FROM factions WHERE factions.name = in_faction_name INTO current_faction_id;
|
|
|
|
RETURN query SELECT ARRAY_AGG((in_faction_name, landsraad_tasks.house_name, task_reveal.revealed, (CASE WHEN winning_faction_id = current_faction_id THEN TRUE ELSE FALSE END), task_progress.participant_count, CAST(landsraad_tasks.board_index AS INTEGER), landsraad_tasks.completion_time)::LandsraadTermTaskTelemetry)
|
|
FROM landsraad_tasks
|
|
LEFT JOIN landsraad_task_reveal_state task_reveal
|
|
ON task_reveal.task_id = landsraad_tasks.id AND task_reveal.faction_id = current_faction_id
|
|
LEFT JOIN LATERAL (
|
|
SELECT COUNT(DISTINCT ltpc.player_id) AS participant_count FROM landsraad_task_player_contributions ltpc WHERE ltpc.task_id = landsraad_tasks.id and ltpc.faction_id = current_faction_id GROUP BY task_id
|
|
) AS task_progress ON true
|
|
WHERE landsraad_tasks.term_id = in_term_id;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_collect_term_telemetry(in_term_id bigint, in_faction_names text[]) -> TABLE(term_telemetry dune.landsraadtermtelemetry[], task_telemetry dune.landsraadtermtasktelemetry[])
|
|
-- oid: 58404 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_collect_term_telemetry(in_term_id bigint, in_faction_names text[])
|
|
RETURNS TABLE(term_telemetry dune.landsraadtermtelemetry[], task_telemetry dune.landsraadtermtasktelemetry[])
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
faction_name TEXT = NULL;
|
|
term_telemetry LandsraadTermTelemetry[];
|
|
task_telemetry LandsraadTermTaskTelemetry[];
|
|
BEGIN
|
|
FOREACH faction_name IN ARRAY in_faction_names
|
|
LOOP
|
|
term_telemetry = ARRAY_APPEND(term_telemetry, landsraad_collect_term_telemetry_for_faction(in_term_id, faction_name));
|
|
task_telemetry = ARRAY_CAT(task_telemetry, landsraad_collect_task_telemetry_for_faction(in_term_id, faction_name));
|
|
END LOOP;
|
|
|
|
RETURN query SELECT term_telemetry, task_telemetry;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_collect_term_telemetry_for_faction(in_term_id bigint, in_faction_name text) -> dune.landsraadtermtelemetry
|
|
-- oid: 58405 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_collect_term_telemetry_for_faction(in_term_id bigint, in_faction_name text)
|
|
RETURNS dune.landsraadtermtelemetry
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
current_faction_id SMALLINT = NULL;
|
|
winning_faction_id SMALLINT = NULL;
|
|
start_time TIMESTAMPTZ = NULL;
|
|
end_time TIMESTAMPTZ = NULL;
|
|
sysselraad_count INTEGER = NULL;
|
|
term_result TEXT = NULL;
|
|
faction_won BOOLEAN = FALSE;
|
|
participants_num_faction INTEGER = NULL;
|
|
tasks_completed INTEGER = NULL;
|
|
tasks_revealed INTEGER = NULL;
|
|
BEGIN
|
|
SELECT id FROM factions WHERE factions.name = in_faction_name INTO current_faction_id;
|
|
|
|
SELECT term.winning_faction_id, term.start_time, term.end_time FROM landsraad_decree_term AS term WHERE term_id = in_term_id INTO winning_faction_id, start_time, end_time;
|
|
|
|
IF winning_faction_id IS NULL THEN
|
|
term_result = 'TIE';
|
|
ELSE
|
|
SELECT COUNT(id) FROM landsraad_tasks WHERE term_id = in_term_id AND sysselraad = true INTO sysselraad_count;
|
|
IF sysselraad_count = 5 THEN
|
|
term_result = 'SYSSELRAAD';
|
|
ELSE
|
|
term_result = 'TASK_COUNT';
|
|
END IF;
|
|
END IF;
|
|
|
|
IF winning_faction_id = current_faction_id THEN
|
|
faction_won = true;
|
|
END IF;
|
|
|
|
SELECT COUNT(DISTINCT player_id) FROM landsraad_task_player_contributions LEFT JOIN landsraad_tasks ON
|
|
landsraad_task_player_contributions.task_id = landsraad_tasks.id
|
|
WHERE landsraad_tasks.term_id = in_term_id AND landsraad_task_player_contributions.faction_id = current_faction_id
|
|
INTO participants_num_faction;
|
|
|
|
SELECT COUNT(id) FROM landsraad_tasks WHERE landsraad_tasks.term_id = in_term_id
|
|
AND landsraad_tasks.winning_faction_id = current_faction_id AND landsraad_tasks.completed = true
|
|
INTO tasks_completed;
|
|
|
|
SELECT COUNT(DISTINCT landsraad_tasks.id) FROM landsraad_task_reveal_state LEFT JOIN landsraad_tasks ON
|
|
landsraad_task_reveal_state.task_id = landsraad_tasks.id
|
|
WHERE landsraad_tasks.term_id = in_term_id AND landsraad_task_reveal_state.faction_id = current_faction_id AND landsraad_task_reveal_state.revealed = true
|
|
INTO tasks_revealed;
|
|
|
|
RETURN (in_faction_name, term_result, faction_won, participants_num_faction, tasks_completed, tasks_revealed, start_time, end_time)::LandsraadTermTelemetry;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_collect_vote_telemetry(in_term_id bigint, in_winning_faction_id integer) -> TABLE(guild_id bigint, decree_name text, voting_influence integer)
|
|
-- oid: 58406 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_collect_vote_telemetry(in_term_id bigint, in_winning_faction_id integer)
|
|
RETURNS TABLE(guild_id bigint, decree_name text, voting_influence integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN query SELECT guild_contribution.guild_id, landsraad_decrees.decree_name, FLOOR(SUM(guild_contribution.amount))::INTEGER
|
|
FROM landsraad_tasks AS tasks
|
|
INNER JOIN landsraad_task_guild_contributions AS guild_contribution
|
|
ON guild_contribution.task_id = tasks.id AND guild_contribution.faction_id = tasks.winning_faction_id AND tasks.term_id = in_term_id AND guild_contribution.faction_id = in_winning_faction_id
|
|
LEFT JOIN landsraad_decree_votes
|
|
ON landsraad_decree_votes.guild_id = guild_contribution.guild_id
|
|
LEFT JOIN landsraad_decrees
|
|
ON landsraad_decree_votes.decree_id = landsraad_decrees.id
|
|
GROUP BY (guild_contribution.guild_id, landsraad_decrees.decree_name);
|
|
END $function$
|
|
|
|
|
|
-- landsraad_collect_votes(in_term_id bigint) -> TABLE(elected_decree text, winning_faction_name text, available_decrees text[], guild_votes dune.landsraadguildvotetelemetry[])
|
|
-- oid: 58407 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_collect_votes(in_term_id bigint)
|
|
RETURNS TABLE(elected_decree text, winning_faction_name text, available_decrees text[], guild_votes dune.landsraadguildvotetelemetry[])
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
has_elected_decree BOOL = FALSE;
|
|
has_winning_faction BOOL = FALSE;
|
|
winning_decree_id BIGINT = NULL;
|
|
winning_decree_name TEXT = NULL;
|
|
winning_faction_name TEXT = NULL;
|
|
winning_faction_id INT = NULL;
|
|
available_decrees TEXT[];
|
|
vote_telemetry LandsraadGuildVoteTelemetry[];
|
|
BEGIN
|
|
LOCK TABLE landsraad_decree_term, landsraad_decree_rotation, landsraad_decree_votes IN EXCLUSIVE MODE;
|
|
|
|
SELECT CASE WHEN landsraad_decree_term.elected_decree_id IS NULL THEN FALSE ELSE TRUE END,
|
|
CASE WHEN landsraad_decree_term.winning_faction_id IS NULL THEN FALSE ELSE TRUE END
|
|
FROM landsraad_decree_term WHERE term_id = in_term_id INTO has_elected_decree, has_winning_faction;
|
|
|
|
IF has_winning_faction IS FALSE THEN
|
|
RETURN query SELECT NULL, NULL, available_decrees, vote_telemetry;
|
|
RETURN;
|
|
END IF;
|
|
|
|
SELECT factions.name, term.winning_faction_id FROM landsraad_decree_term AS term LEFT JOIN factions ON term.winning_faction_id = factions.id WHERE term.term_id = in_term_id INTO winning_faction_name, winning_faction_id;
|
|
|
|
SELECT ARRAY_AGG(landsraad_decrees.decree_name) FROM landsraad_decree_rotation INNER JOIN landsraad_decrees ON landsraad_decree_rotation.decree_id = landsraad_decrees.id INTO available_decrees;
|
|
|
|
SELECT ARRAY_AGG((guild_id, decree_name, voting_influence)::LandsraadGuildVoteTelemetry) FROM landsraad_collect_vote_telemetry(in_term_id, winning_faction_id) INTO vote_telemetry;
|
|
|
|
-- Only resolve votes if the latest term has no elected decree
|
|
IF has_elected_decree IS FALSE THEN
|
|
WITH
|
|
votes AS (SELECT decree_id, SUM(influence) AS amount FROM landsraad_decree_votes GROUP BY decree_id),
|
|
max_votes AS (SELECT MAX(amount) AS amount FROM votes)
|
|
UPDATE landsraad_decree_term
|
|
SET elected_decree_id =
|
|
CASE WHEN (SELECT amount FROM max_votes) IS NOT NULL THEN
|
|
(SELECT decree_id FROM votes WHERE amount = (SELECT amount FROM max_votes) ORDER BY RANDOM() LIMIT 1)
|
|
ELSE
|
|
(SELECT decree_id FROM landsraad_decree_rotation ORDER BY RANDOM() LIMIT 1)
|
|
END
|
|
WHERE term_id = in_term_id
|
|
returning elected_decree_id INTO winning_decree_id;
|
|
ELSE
|
|
SELECT term.elected_decree_id FROM landsraad_decree_term term ORDER BY term_id DESC LIMIT 1 INTO winning_decree_id;
|
|
END IF;
|
|
|
|
SELECT decree_name FROM landsraad_decrees WHERE id = winning_decree_id INTO winning_decree_name;
|
|
|
|
RETURN query SELECT winning_decree_name, winning_faction_name, available_decrees, vote_telemetry;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_determine_winner(in_term_id bigint) -> text
|
|
-- oid: 58408 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_determine_winner(in_term_id bigint)
|
|
RETURNS text
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
has_winning_faction BOOLEAN = FALSE;
|
|
winning_faction_name TEXT = NULL;
|
|
BEGIN
|
|
SELECT CASE WHEN winning_faction_id IS NULL THEN FALSE ELSE TRUE END FROM landsraad_decree_term WHERE term_id = in_term_id INTO has_winning_faction;
|
|
|
|
-- only set winning faction if not set already (sysselraad has been secured)
|
|
IF NOT has_winning_faction THEN
|
|
WITH tasks_completed_by_faction AS (SELECT winning_faction_id AS faction, COUNT(id) AS num_tasks FROM landsraad_tasks WHERE term_id = in_term_id AND winning_faction_id IS NOT NULL GROUP BY (winning_faction_id)),
|
|
winner_count AS (SELECT COUNT(faction) AS amount FROM tasks_completed_by_faction WHERE num_tasks = (SELECT MAX(num_tasks) FROM tasks_completed_by_faction) GROUP BY(num_tasks)),
|
|
winner AS (SELECT faction FROM tasks_completed_by_faction ORDER BY num_tasks DESC LIMIT 1)
|
|
UPDATE landsraad_decree_term SET winning_faction_id = CASE WHEN winner_count.amount = 1 THEN winner.faction ELSE NULL END FROM winner, winner_count;
|
|
PERFORM pg_notify('landsraad_notify_channel', 'state_changed');
|
|
END IF;
|
|
|
|
SELECT factions.name FROM landsraad_decree_term AS term LEFT JOIN factions ON term.winning_faction_id = factions.id WHERE term.term_id = in_term_id INTO winning_faction_name;
|
|
|
|
RETURN winning_faction_name;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_force_end_term(end_term_id bigint) -> void
|
|
-- oid: 58409 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_force_end_term(end_term_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM landsraad_change_term_end_time(end_term_id, now() AT TIME ZONE 'UTC', false);
|
|
END $function$
|
|
|
|
|
|
-- landsraad_has_term_of_task_ended(in_task_id bigint) -> boolean
|
|
-- oid: 58410 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_has_term_of_task_ended(in_task_id bigint)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
term_ended BOOLEAN = FALSE;
|
|
BEGIN
|
|
SELECT NOW() > term.end_time FROM landsraad_tasks AS task LEFT JOIN landsraad_decree_term AS term ON task.term_id = term.term_id WHERE task.id = in_task_id INTO term_ended;
|
|
RETURN term_ended;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_initialize_system(number_of_weeks_term_retention integer, number_of_nominated_decrees integer, in_end_time timestamp without time zone, in_test_term boolean, faction_names text[], decrees dune.landsraaddecree[], tasks dune.landsraadtask[], task_rewards dune.landsraadtaskreward[]) -> TABLE(term_id bigint, reigning_faction_name text, active_decree_name text, winning_faction_name text, elected_decree_name text, start_time timestamp without time zone, end_time timestamp without time zone)
|
|
-- oid: 58411 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_initialize_system(number_of_weeks_term_retention integer, number_of_nominated_decrees integer, in_end_time timestamp without time zone, in_test_term boolean, faction_names text[], decrees dune.landsraaddecree[], tasks dune.landsraadtask[], task_rewards dune.landsraadtaskreward[])
|
|
RETURNS TABLE(term_id bigint, reigning_faction_name text, active_decree_name text, winning_faction_name text, elected_decree_name text, start_time timestamp without time zone, end_time timestamp without time zone)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
current_term_id BIGINT = NULL;
|
|
BEGIN
|
|
LOCK TABLE landsraad_decree_term, landsraad_decree_rotation, landsraad_decrees, landsraad_decree_votes IN EXCLUSIVE MODE;
|
|
|
|
CALL landsraad_update_decrees(decrees);
|
|
|
|
CALL landsraad_update_factions(faction_names);
|
|
|
|
SELECT term.term_id FROM landsraad_decree_term term ORDER BY term.term_id DESC LIMIT 1 INTO current_term_id;
|
|
IF FOUND THEN
|
|
RETURN query SELECT term.term_id, reigning_faction.name, active_decree.decree_name, winning_faction.name, elected_decree.decree_name, (term.start_time AT TIME ZONE 'UTC')::TIMESTAMP, (term.end_time AT TIME ZONE 'UTC')::TIMESTAMP
|
|
FROM landsraad_decree_term term
|
|
LEFT JOIN factions reigning_faction ON term.reigning_faction_id = reigning_faction.id
|
|
LEFT JOIN landsraad_decrees active_decree ON term.active_decree_id = active_decree.id
|
|
LEFT JOIN factions winning_faction ON term.winning_faction_id = winning_faction.id
|
|
LEFT JOIN landsraad_decrees elected_decree ON term.elected_decree_id = elected_decree.id
|
|
WHERE term.term_id = current_term_id;
|
|
ELSE
|
|
RETURN query SELECT term.term_id, term.reigning_faction_name, term.active_decree_name, term.winning_faction_name, term.elected_decree_name, term.start_time, term.end_time
|
|
FROM landsraad_initialize_term(number_of_weeks_term_retention, number_of_nominated_decrees, in_end_time, in_test_term, tasks, task_rewards) AS term;
|
|
END IF;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_initialize_term(number_of_weeks_term_retention integer, number_of_nominated_decrees integer, in_end_time timestamp without time zone, in_test_term boolean, tasks dune.landsraadtask[], task_rewards dune.landsraadtaskreward[]) -> TABLE(term_id bigint, reigning_faction_name text, active_decree_name text, winning_faction_name text, elected_decree_name text, start_time timestamp without time zone, end_time timestamp without time zone)
|
|
-- oid: 58412 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_initialize_term(number_of_weeks_term_retention integer, number_of_nominated_decrees integer, in_end_time timestamp without time zone, in_test_term boolean, tasks dune.landsraadtask[], task_rewards dune.landsraadtaskreward[])
|
|
RETURNS TABLE(term_id bigint, reigning_faction_name text, active_decree_name text, winning_faction_name text, elected_decree_name text, start_time timestamp without time zone, end_time timestamp without time zone)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
reigning_faction_id SMALLINT = NULL;
|
|
active_decree_id BIGINT = NULL;
|
|
last_active_decree_id BIGINT = NULL;
|
|
current_term_id BIGINT = NULL;
|
|
BEGIN
|
|
LOCK TABLE landsraad_decrees, landsraad_decree_term, landsraad_decree_rotation, landsraad_decree_votes IN EXCLUSIVE MODE;
|
|
|
|
-- read winning faction, elected and active decree from previous term
|
|
SELECT term.winning_faction_id, term.elected_decree_id, term.active_decree_id INTO reigning_faction_id, active_decree_id, last_active_decree_id FROM landsraad_decree_term term ORDER BY term.term_id DESC LIMIT 1;
|
|
|
|
-- insert new term
|
|
INSERT INTO landsraad_decree_term (reigning_faction_id, active_decree_id, start_time, end_time, test_term) VALUES(reigning_faction_id, active_decree_id, now(), in_end_time AT TIME ZONE 'UTC', in_test_term) RETURNING landsraad_decree_term.term_id INTO current_term_id;
|
|
|
|
-- cleanup old terms, except for previous one
|
|
DELETE FROM landsraad_decree_term term WHERE term.end_time < (now() - MAKE_INTERVAL(weeks => number_of_weeks_term_retention)) AND term.term_id < current_term_id - 1;
|
|
|
|
-- insert tasks for new term
|
|
CALL landsraad_insert_tasks(current_term_id, tasks, task_rewards);
|
|
|
|
-- insert decrees for voting
|
|
CALL landsraad_nominate_decrees_for_voting(last_active_decree_id, number_of_nominated_decrees);
|
|
|
|
-- clean expired landsraad contracts
|
|
PERFORM journey_story_node_cooldown_delete_expired(now() at time zone 'utc');
|
|
|
|
RETURN query SELECT term.term_id, reigning_faction.name, active_decree.decree_name, winning_faction.name, elected_decree.decree_name, (term.start_time AT TIME ZONE 'UTC')::TIMESTAMP, (term.end_time AT TIME ZONE 'UTC')::TIMESTAMP
|
|
FROM landsraad_decree_term term
|
|
LEFT JOIN factions reigning_faction ON term.reigning_faction_id = reigning_faction.id
|
|
LEFT JOIN landsraad_decrees active_decree ON term.active_decree_id = active_decree.id
|
|
LEFT JOIN factions winning_faction ON term.winning_faction_id = winning_faction.id
|
|
LEFT JOIN landsraad_decrees elected_decree ON term.elected_decree_id = elected_decree.id
|
|
WHERE term.term_id = current_term_id;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_insert_task_progress(in_term_id bigint, in_player_id bigint, in_guild_id bigint, in_house_name text, in_faction_progress integer, in_guild_progress real, in_player_progress real, in_timestamp timestamp without time zone) -> void
|
|
-- oid: 58413 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_insert_task_progress(in_term_id bigint, in_player_id bigint, in_guild_id bigint, in_house_name text, in_faction_progress integer, in_guild_progress real, in_player_progress real, in_timestamp timestamp without time zone)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
guild_id BIGINT = NULL;
|
|
faction_id BIGINT = NULL;
|
|
faction_name TEXT = NULL;
|
|
progress_id BIGINT = NULL;
|
|
BEGIN
|
|
|
|
IF in_player_id IS NULL THEN
|
|
-- use guild_id
|
|
SELECT guilds.guild_id, factions.id, factions.name FROM guild_members
|
|
INNER JOIN guilds ON guild_members.guild_id = guilds.guild_id
|
|
LEFT JOIN factions ON guilds.guild_faction = factions.id
|
|
WHERE guild_members.guild_id = in_guild_id INTO guild_id, faction_id, faction_name;
|
|
ELSE
|
|
-- use player_id
|
|
SELECT guilds.guild_id, factions.id, factions.name FROM guild_members
|
|
INNER JOIN guilds ON guild_members.guild_id = guilds.guild_id
|
|
LEFT JOIN factions ON guilds.guild_faction = factions.id
|
|
WHERE guild_members.player_id = in_player_id INTO guild_id, faction_id, faction_name;
|
|
END IF;
|
|
|
|
IF guild_id IS NULL THEN
|
|
RAISE EXCEPTION 'Cannot insert landsraad task progress, player % not in guild', in_player_id;
|
|
END IF;
|
|
|
|
IF faction_id IS NULL OR faction_name = 'None' THEN
|
|
RAISE EXCEPTION 'Cannot insert landsraad task progress, guild % not aligned to faction', guild_id;
|
|
END IF;
|
|
|
|
INSERT INTO landsraad_task_progress (faction_id, task_id, faction_progress, guild_progress, player_progress, timestamp)
|
|
SELECT faction_id, tasks.id, in_faction_progress, in_guild_progress, in_player_progress, in_timestamp AT TIME ZONE 'UTC'
|
|
FROM landsraad_tasks AS tasks
|
|
WHERE tasks.term_id = in_term_id AND tasks.house_name = in_house_name
|
|
RETURNING id INTO progress_id;
|
|
|
|
IF in_player_id IS NOT NULL THEN
|
|
INSERT INTO landsraad_task_progress_player (progress_id, player_id) VALUES (progress_id, in_player_id);
|
|
END IF;
|
|
|
|
INSERT INTO landsraad_task_progress_guild (progress_id, guild_id) VALUES (progress_id, guild_id);
|
|
|
|
END $function$
|
|
|
|
|
|
-- landsraad_insert_task_progress_batched(in_term_id bigint, in_task_progress dune.landsraadtaskprogress[]) -> void
|
|
-- oid: 58414 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_insert_task_progress_batched(in_term_id bigint, in_task_progress dune.landsraadtaskprogress[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
task_progress record = NULL;
|
|
BEGIN
|
|
FOREACH task_progress IN ARRAY in_task_progress
|
|
LOOP
|
|
PERFORM landsraad_insert_task_progress(in_term_id, task_progress.player_id, task_progress.guild_id ,task_progress.house_name, task_progress.faction_progress, task_progress.guild_progress, task_progress.player_progress, task_progress.timestamp);
|
|
END LOOP;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_insert_task_progress_faction(in_term_id bigint, in_faction_name text, in_house_name text, in_faction_progress integer, in_guild_progress real, in_player_progress real) -> void
|
|
-- oid: 58415 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_insert_task_progress_faction(in_term_id bigint, in_faction_name text, in_house_name text, in_faction_progress integer, in_guild_progress real, in_player_progress real)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
player_id BIGINT = NULL;
|
|
guild_id BIGINT = NULL;
|
|
BEGIN
|
|
SELECT guild_members.player_id, guilds.guild_id FROM guilds
|
|
LEFT JOIN factions ON guilds.guild_faction = factions.id
|
|
RIGHT JOIN guild_members ON guild_members.guild_id = guilds.guild_id
|
|
WHERE factions.name = in_faction_name
|
|
ORDER BY random() LIMIT 1 INTO player_id, guild_id;
|
|
|
|
IF player_id IS NULL THEN
|
|
RAISE EXCEPTION 'Cannot insert landsraad task progress for faction %, no guild member found', in_faction_name;
|
|
END IF;
|
|
|
|
PERFORM landsraad_insert_task_progress(in_term_id, player_id, guild_id, in_house_name, in_faction_progress, in_guild_progress, in_player_progress, now() AT TIME ZONE 'UTC');
|
|
END $function$
|
|
|
|
|
|
-- landsraad_insert_task_progress_random(in_term_id bigint, in_faction_names text[], in_num_rows integer) -> void
|
|
-- oid: 58416 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_insert_task_progress_random(in_term_id bigint, in_faction_names text[], in_num_rows integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
player_id BIGINT = NULL;
|
|
guild_id BIGINT = NULL;
|
|
house_name TEXT = NULL;
|
|
random_amount INTEGER = NULL;
|
|
BEGIN
|
|
FOR r IN 1..in_num_rows
|
|
LOOP
|
|
SELECT guild_members.player_id, guilds.guild_id FROM guilds
|
|
LEFT JOIN factions ON guilds.guild_faction = factions.id
|
|
RIGHT JOIN guild_members ON guild_members.guild_id = guilds.guild_id
|
|
WHERE factions.name = ANY(in_faction_names)
|
|
ORDER BY random() LIMIT 1 INTO player_id, guild_id;
|
|
SELECT tasks.house_name FROM landsraad_tasks tasks
|
|
WHERE tasks.term_id = in_term_id
|
|
ORDER BY random() LIMIT 1 INTO house_name;
|
|
SELECT (floor(random() * 5) + 1)::INTEGER * 10 INTO random_amount;
|
|
IF player_id IS NOT NULL AND house_name IS NOT NULL THEN
|
|
PERFORM landsraad_insert_task_progress(in_term_id, player_id, guild_id, house_name, random_amount * 10, (random_amount * 0.1)::REAL, (random_amount * 10)::REAL, now() AT TIME ZONE 'UTC');
|
|
END IF;
|
|
END LOOP;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_insert_tasks(IN in_term_id bigint, IN in_tasks dune.landsraadtask[], IN in_task_rewards dune.landsraadtaskreward[]) -> void
|
|
-- oid: 58417 kind: PROCEDURE category: landsraad
|
|
|
|
CREATE OR REPLACE PROCEDURE dune.landsraad_insert_tasks(IN in_term_id bigint, IN in_tasks dune.landsraadtask[], IN in_task_rewards dune.landsraadtaskreward[])
|
|
LANGUAGE plpgsql
|
|
AS $procedure$
|
|
BEGIN
|
|
INSERT INTO landsraad_tasks (term_id, board_index, house_name, goal_amount)
|
|
SELECT in_term_id, tasks.board_index, tasks.house_name, tasks.goal_amount FROM UNNEST(in_tasks) AS tasks;
|
|
|
|
INSERT INTO landsraad_task_rewards (task_id, threshold, template_id, amount)
|
|
SELECT tasks.id, task_rewards.threshold, task_rewards.template_id, task_rewards.amount FROM UNNEST(in_task_rewards) AS task_rewards
|
|
LEFT JOIN landsraad_tasks AS tasks ON task_rewards.house_name = tasks.house_name WHERE tasks.term_id = in_term_id;
|
|
END $procedure$
|
|
|
|
|
|
-- landsraad_load_current_rotation(in_term_id bigint) -> TABLE(decree_name text, received_votes integer, open_votes integer)
|
|
-- oid: 58418 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_current_rotation(in_term_id bigint)
|
|
RETURNS TABLE(decree_name text, received_votes integer, open_votes integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
open_votes INTEGER = 0;
|
|
BEGIN
|
|
WITH open_guild_votes AS (
|
|
SELECT guild_contribution.guild_id, FLOOR(SUM(guild_contribution.amount))::INTEGER AS voting_influence
|
|
FROM landsraad_tasks AS tasks
|
|
INNER JOIN landsraad_task_guild_contributions AS guild_contribution
|
|
ON guild_contribution.task_id = tasks.id AND guild_contribution.faction_id = tasks.winning_faction_id
|
|
LEFT JOIN landsraad_decree_votes
|
|
ON guild_contribution.guild_id = landsraad_decree_votes.guild_id
|
|
WHERE tasks.term_id = in_term_id AND tasks.winning_faction_id = (SELECT winning_faction_id FROM landsraad_decree_term WHERE term_id = in_term_id)
|
|
AND landsraad_decree_votes.guild_id IS NULL
|
|
GROUP BY (guild_contribution.guild_id, guild_contribution.faction_id)
|
|
)
|
|
SELECT SUM(voting_influence)::INTEGER FROM open_guild_votes INTO open_votes;
|
|
|
|
RETURN query (
|
|
SELECT decrees.decree_name, SUM(decree_votes.influence)::INTEGER AS received_votes, open_votes
|
|
FROM landsraad_decree_rotation AS rotation
|
|
INNER JOIN landsraad_decrees AS decrees ON rotation.decree_id = decrees.id
|
|
LEFT JOIN landsraad_decree_votes AS decree_votes ON decree_votes.decree_id = rotation.decree_id
|
|
GROUP BY rotation.decree_id, decrees.decree_name
|
|
);
|
|
END $function$
|
|
|
|
|
|
-- landsraad_load_current_term() -> TABLE(term_id bigint, reigning_faction_name text, active_decree_name text, winning_faction_name text, elected_decree_name text, start_time timestamp without time zone, end_time timestamp without time zone, tasks dune.landsraadtask[], term_task_rewards dune.landsraadtaskreward[], winner_history text[], testterm boolean)
|
|
-- oid: 58419 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_current_term()
|
|
RETURNS TABLE(term_id bigint, reigning_faction_name text, active_decree_name text, winning_faction_name text, elected_decree_name text, start_time timestamp without time zone, end_time timestamp without time zone, tasks dune.landsraadtask[], term_task_rewards dune.landsraadtaskreward[], winner_history text[], testterm boolean)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
current_term_id BIGINT = NULL;
|
|
reigning_faction_name TEXT = NULL;
|
|
active_decree_name TEXT = NULL;
|
|
winning_faction_name TEXT = NULL;
|
|
elected_decree_name TEXT = NULL;
|
|
start_time TIMESTAMP = NULL;
|
|
end_time TIMESTAMP = NULL;
|
|
test_term BOOL = NULL;
|
|
term_tasks LandsraadTask[];
|
|
term_task_rewards LandsraadTaskReward[];
|
|
term_winner_history TEXT[];
|
|
BEGIN
|
|
SELECT term.term_id, reigning_faction.name, active_decree.decree_name, winning_faction.name, elected_decree.decree_name, (term.start_time AT TIME ZONE 'UTC')::TIMESTAMP, (term.end_time AT TIME ZONE 'UTC')::TIMESTAMP, term.test_term
|
|
INTO current_term_id, reigning_faction_name, active_decree_name, winning_faction_name, elected_decree_name, start_time, end_time, test_term
|
|
FROM landsraad_decree_term AS term
|
|
LEFT JOIN factions AS reigning_faction ON term.reigning_faction_id = reigning_faction.id
|
|
LEFT JOIN landsraad_decrees AS active_decree ON term.active_decree_id = active_decree.id
|
|
LEFT JOIN factions AS winning_faction ON term.winning_faction_id = winning_faction.id
|
|
LEFT JOIN landsraad_decrees AS elected_decree ON term.elected_decree_id = elected_decree.id
|
|
ORDER BY term.start_time DESC LIMIT 1;
|
|
|
|
SELECT ARRAY_AGG((tasks.board_index, tasks.house_name, tasks.completed, COALESCE(factions_winner.name, ''), tasks.sysselraad, tasks.goal_amount)::LandsraadTask)
|
|
INTO term_tasks
|
|
FROM landsraad_tasks AS tasks
|
|
LEFT JOIN factions AS factions_winner ON tasks.winning_faction_id = factions_winner.id
|
|
WHERE tasks.term_id = current_term_id;
|
|
|
|
WITH task_rewards AS (
|
|
SELECT tasks.house_name AS house_name, rewards.threshold AS threshold, rewards.template_id AS template_id, rewards.amount AS amount
|
|
FROM landsraad_task_rewards AS rewards
|
|
LEFT JOIN landsraad_tasks AS tasks ON rewards.task_id = tasks.id
|
|
WHERE tasks.term_id = current_term_id ORDER BY rewards.task_id ASC, rewards.threshold ASC
|
|
)
|
|
SELECT ARRAY_AGG((house_name, threshold, template_id, amount)::LandsraadTaskReward) FROM task_rewards INTO term_task_rewards;
|
|
|
|
SELECT ARRAY_AGG(winning_factions.name::TEXT)
|
|
INTO term_winner_history
|
|
FROM
|
|
(SELECT factions.name
|
|
FROM landsraad_decree_term
|
|
LEFT JOIN factions ON landsraad_decree_term.reigning_faction_id = factions.id
|
|
ORDER BY landsraad_decree_term.term_id DESC) AS winning_factions;
|
|
|
|
IF current_term_id IS NOT NULL THEN
|
|
RETURN query SELECT current_term_id, reigning_faction_name, active_decree_name, winning_faction_name, elected_decree_name, start_time, end_time, term_tasks, term_task_rewards, term_winner_history, test_term;
|
|
END IF;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_load_guild_contribution(in_term_id bigint, in_guild_id bigint, in_faction_id bigint) -> TABLE(voting_influence real)
|
|
-- oid: 58420 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_guild_contribution(in_term_id bigint, in_guild_id bigint, in_faction_id bigint)
|
|
RETURNS TABLE(voting_influence real)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN query (
|
|
SELECT SUM(guild_contribution.amount)::REAL
|
|
FROM landsraad_tasks AS tasks
|
|
INNER JOIN landsraad_task_guild_contributions AS guild_contribution
|
|
ON guild_contribution.task_id = tasks.id
|
|
WHERE tasks.term_id = in_term_id AND guild_contribution.guild_id = in_guild_id AND guild_contribution.faction_id = in_faction_id
|
|
GROUP BY (guild_contribution.guild_id, guild_contribution.faction_id)
|
|
);
|
|
END $function$
|
|
|
|
|
|
-- landsraad_load_guild_contributions(in_term_id bigint, in_num_guilds integer, in_faction_names text[]) -> TABLE(faction_name text, guild_name text, voting_influence real)
|
|
-- oid: 58421 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_guild_contributions(in_term_id bigint, in_num_guilds integer, in_faction_names text[])
|
|
RETURNS TABLE(faction_name text, guild_name text, voting_influence real)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN query (
|
|
SELECT factions.name, top_guilds.guild_name, top_guilds.influence FROM factions
|
|
CROSS JOIN LATERAL (
|
|
SELECT guilds.guild_name as guild_name, SUM(guild_contribution.amount)::REAL AS influence
|
|
FROM landsraad_tasks AS tasks
|
|
INNER JOIN landsraad_task_guild_contributions AS guild_contribution
|
|
ON guild_contribution.task_id = tasks.id AND guild_contribution.faction_id = factions.id
|
|
JOIN guilds
|
|
ON guild_contribution.guild_id = guilds.guild_id
|
|
WHERE tasks.term_id = in_term_id
|
|
GROUP BY (guilds.guild_id, guilds.guild_name)
|
|
ORDER BY influence DESC LIMIT in_num_guilds
|
|
) AS top_guilds
|
|
WHERE factions.name = ANY(in_faction_names)
|
|
);
|
|
END $function$
|
|
|
|
|
|
-- landsraad_load_guild_vote(in_term_id bigint, in_player_id bigint) -> TABLE(decree_name text, voting_influence real)
|
|
-- oid: 58422 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_guild_vote(in_term_id bigint, in_player_id bigint)
|
|
RETURNS TABLE(decree_name text, voting_influence real)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
term_winning_faction_id SMALLINT = NULL;
|
|
player_guild_id BIGINT = NULL;
|
|
guild_faction_id SMALLINT = NULL;
|
|
BEGIN
|
|
SELECT guilds.guild_id, guilds.guild_faction FROM guild_members JOIN guilds ON guild_members.guild_id = guilds.guild_id WHERE guild_members.player_id = in_player_id INTO player_guild_id, guild_faction_id;
|
|
|
|
RETURN query (
|
|
SELECT
|
|
CASE WHEN player_guild_id IS NOT NULL AND guild_faction_id IS NOT NULL THEN
|
|
(SELECT COALESCE(decrees.decree_name, '') FROM landsraad_decree_votes AS votes LEFT JOIN landsraad_decrees AS decrees ON votes.decree_id = decrees.id WHERE votes.guild_id = player_guild_id)
|
|
ELSE
|
|
''
|
|
END,
|
|
CASE WHEN player_guild_id IS NOT NULL AND guild_faction_id IS NOT NULL THEN
|
|
(SELECT landsraad_load_guild_contribution(in_term_id, player_guild_id, guild_faction_id))
|
|
ELSE
|
|
0
|
|
END
|
|
);
|
|
END $function$
|
|
|
|
|
|
-- landsraad_load_house_rewards(in_player_id bigint) -> TABLE(house_name text, template_id text, amount integer, last_updated timestamp without time zone)
|
|
-- oid: 58423 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_house_rewards(in_player_id bigint)
|
|
RETURNS TABLE(house_name text, template_id text, amount integer, last_updated timestamp without time zone)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN query (SELECT rewards.house_name, rewards.template_id, rewards.amount, (rewards.last_updated AT TIME ZONE 'UTC')::TIMESTAMP FROM landsraad_house_rewards AS rewards WHERE player_id = in_player_id AND rewards.amount > 0);
|
|
END $function$
|
|
|
|
|
|
-- landsraad_load_player_contributions(in_term_id bigint, in_player_ids bigint[]) -> TABLE(player_id bigint, board_index smallint, amount integer)
|
|
-- oid: 58424 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_player_contributions(in_term_id bigint, in_player_ids bigint[])
|
|
RETURNS TABLE(player_id bigint, board_index smallint, amount integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN query (
|
|
SELECT contributions.player_id, tasks.board_index, FLOOR(SUM(contributions.amount))::INTEGER FROM landsraad_task_player_contributions AS contributions
|
|
INNER JOIN landsraad_tasks AS tasks ON contributions.task_id = tasks.id
|
|
WHERE tasks.term_id = in_term_id AND contributions.player_id = ANY(in_player_ids)
|
|
GROUP BY contributions.player_id, tasks.board_index
|
|
);
|
|
END $function$
|
|
|
|
|
|
-- landsraad_load_task_faction_progress(in_term_id bigint) -> TABLE(task_board_index integer, faction_name text, progress integer)
|
|
-- oid: 58425 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_task_faction_progress(in_term_id bigint)
|
|
RETURNS TABLE(task_board_index integer, faction_name text, progress integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN query SELECT CAST(faction_progress.board_index AS INTEGER), faction_progress.name, CAST(faction_progress.progress AS INTEGER) FROM
|
|
(SELECT tasks.id, tasks.board_index, factions.name, SUM(faction_contribution.amount) AS progress
|
|
FROM landsraad_tasks tasks
|
|
INNER JOIN landsraad_task_faction_contributions faction_contribution
|
|
ON faction_contribution.task_id = tasks.id
|
|
LEFT JOIN factions factions
|
|
ON factions.id = faction_contribution.faction_id
|
|
WHERE tasks.term_id = in_term_id
|
|
GROUP BY (tasks.id, tasks.board_index, factions.name)) AS faction_progress;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_load_task_faction_reveal_state(in_term_id bigint) -> TABLE(task_board_index integer, faction_name text, reveal_state boolean, time_stamp timestamp without time zone)
|
|
-- oid: 58426 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_task_faction_reveal_state(in_term_id bigint)
|
|
RETURNS TABLE(task_board_index integer, faction_name text, reveal_state boolean, time_stamp timestamp without time zone)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN query SELECT CAST(tasks.board_index AS INTEGER), factions.name, reveal_state.revealed, (reveal_state.timestamp AT TIME ZONE 'UTC')::TIMESTAMP
|
|
FROM landsraad_tasks tasks
|
|
INNER JOIN landsraad_task_reveal_state reveal_state
|
|
ON reveal_state.task_id = tasks.id
|
|
INNER JOIN factions factions
|
|
ON factions.id = reveal_state.faction_id
|
|
WHERE tasks.term_id = in_term_id;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_load_term_progress(in_term_id bigint, in_num_guilds integer, in_faction_names text[], in_player_ids bigint[]) -> TABLE(faction_progress dune.landsraadtaskfactionprogress[], faction_reveal_state dune.landsraadtaskfactionrevealstate[], guild_contributions dune.landsraadguildcontribution[], player_contributions dune.landsraadplayercontribution[])
|
|
-- oid: 58427 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_load_term_progress(in_term_id bigint, in_num_guilds integer, in_faction_names text[], in_player_ids bigint[])
|
|
RETURNS TABLE(faction_progress dune.landsraadtaskfactionprogress[], faction_reveal_state dune.landsraadtaskfactionrevealstate[], guild_contributions dune.landsraadguildcontribution[], player_contributions dune.landsraadplayercontribution[])
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
term_faction_progress LandsraadTaskFactionProgress[];
|
|
term_faction_reveal_state LandsraadTaskFactionRevealState[];
|
|
term_guild_contributions LandsraadGuildContribution[];
|
|
term_player_contributions LandsraadPlayerContribution[];
|
|
BEGIN
|
|
SELECT ARRAY_AGG((task_board_index, faction_name, progress)::LandsraadTaskFactionProgress) FROM landsraad_load_task_faction_progress(in_term_id) INTO term_faction_progress;
|
|
SELECT ARRAY_AGG((task_board_index, faction_name, reveal_state, time_stamp)::LandsraadTaskFactionRevealState) FROM landsraad_load_task_faction_reveal_state(in_term_id) INTO term_faction_reveal_state;
|
|
SELECT ARRAY_AGG((faction_name, guild_name, voting_influence)::LandsraadGuildContribution) FROM landsraad_load_guild_contributions(in_term_id, in_num_guilds, in_faction_names) INTO term_guild_contributions;
|
|
SELECT ARRAY_AGG((player_id, board_index, amount)::LandsraadPlayerContribution) FROM landsraad_load_player_contributions(in_term_id, in_player_ids) INTO term_player_contributions;
|
|
|
|
RETURN query SELECT term_faction_progress, term_faction_reveal_state, term_guild_contributions, term_player_contributions;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_nominate_decrees_for_voting(IN last_active_decree_id bigint, IN num_decrees integer) -> void
|
|
-- oid: 58428 kind: PROCEDURE category: landsraad
|
|
|
|
CREATE OR REPLACE PROCEDURE dune.landsraad_nominate_decrees_for_voting(IN last_active_decree_id bigint, IN num_decrees integer)
|
|
LANGUAGE plpgsql
|
|
AS $procedure$
|
|
BEGIN
|
|
LOCK TABLE landsraad_decrees, landsraad_decree_rotation, landsraad_decree_votes IN EXCLUSIVE MODE;
|
|
|
|
TRUNCATE TABLE landsraad_decree_votes;
|
|
TRUNCATE TABLE landsraad_decree_rotation;
|
|
|
|
INSERT INTO landsraad_decree_rotation
|
|
SELECT id FROM landsraad_decrees
|
|
WHERE (
|
|
CASE WHEN last_active_decree_id IS NULL THEN
|
|
True
|
|
ELSE
|
|
last_active_decree_id != id
|
|
END
|
|
) AND disabled = FALSE
|
|
ORDER BY RANDOM() * weight DESC
|
|
LIMIT num_decrees;
|
|
END $procedure$
|
|
|
|
|
|
-- landsraad_notify_house_rewards_changed() -> trigger
|
|
-- oid: 58429 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_notify_house_rewards_changed()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM pg_notify('landsraad_notify_channel', format('house_rewards_changed#{"PlayerId" : %s}', NEW.player_id));
|
|
RETURN NULL;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_perform_daily_task_reveal(in_term_id bigint, in_faction_names text[], in_house_names_to_reveal text[], in_reveal_day integer) -> TABLE(faction_name text, house_name text, board_index integer)
|
|
-- oid: 58430 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_perform_daily_task_reveal(in_term_id bigint, in_faction_names text[], in_house_names_to_reveal text[], in_reveal_day integer)
|
|
RETURNS TABLE(faction_name text, house_name text, board_index integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
last_processed_reveal_day INTEGER = NULL;
|
|
faction_ids BIGINT[];
|
|
newly_revealed_task_ids BIGINT[];
|
|
newly_revealed_house_names TEXT[];
|
|
newly_revealed_task_board_indices INTEGER[];
|
|
faction_of_newly_revealed_task BIGINT[];
|
|
BEGIN
|
|
LOCK TABLE landsraad_decree_term IN EXCLUSIVE MODE;
|
|
|
|
SELECT landsraad_decree_term.last_processed_reveal_day FROM landsraad_decree_term WHERE term_id = in_term_id INTO last_processed_reveal_day;
|
|
|
|
IF last_processed_reveal_day < in_reveal_day THEN
|
|
SELECT ARRAY_AGG(factions.id) FROM factions WHERE factions.name = ANY(in_faction_names) INTO faction_ids;
|
|
|
|
WITH revealed_task(id, faction_id) AS (
|
|
SELECT task.id, faction.id FROM landsraad_tasks AS task
|
|
CROSS JOIN UNNEST(faction_ids) AS faction(id)
|
|
WHERE task.house_name = ANY (in_house_names_to_reveal) AND task.term_id = in_term_id)
|
|
--filter out tasks already revealed from data to not stomp reveal date or send duplicate reveal event in telemetry
|
|
SELECT ARRAY_AGG(task.id), ARRAY_AGG(task.house_name), ARRAY_AGG(task.board_index), ARRAY_AGG(revealed_task.faction_id) FROM revealed_task
|
|
INNER JOIN landsraad_tasks AS task ON task.id = revealed_task.id
|
|
LEFT JOIN landsraad_task_reveal_state AS reveal_state ON task.id = reveal_state.task_id AND revealed_task.faction_id = reveal_state.faction_id
|
|
WHERE reveal_state.revealed IS NULL OR reveal_state.revealed IS FALSE
|
|
INTO newly_revealed_task_ids, newly_revealed_house_names, newly_revealed_task_board_indices, faction_of_newly_revealed_task;
|
|
|
|
INSERT INTO landsraad_task_reveal_state (task_id, faction_id, revealed, timestamp) SELECT UNNEST(newly_revealed_task_ids), UNNEST(faction_of_newly_revealed_task), TRUE, now()
|
|
ON CONFLICT(task_id, faction_id) DO UPDATE SET revealed = TRUE, timestamp = now();
|
|
|
|
UPDATE landsraad_decree_term SET last_processed_reveal_day = in_reveal_day WHERE term_id = in_term_id;
|
|
|
|
IF cardinality(newly_revealed_task_ids) > 0 THEN
|
|
PERFORM pg_notify('landsraad_notify_channel', 'progress_updated#{"changed": true}');
|
|
END IF;
|
|
END IF;
|
|
|
|
RETURN query
|
|
WITH newly_revealed_tasks (house_name, board_index, faction_id) AS (
|
|
SELECT UNNEST(newly_revealed_house_names), UNNEST(newly_revealed_task_board_indices), UNNEST(faction_of_newly_revealed_task))
|
|
SELECT factions.name, newly_revealed_tasks.house_name, newly_revealed_tasks.board_index FROM newly_revealed_tasks JOIN factions ON newly_revealed_tasks.faction_id = factions.id;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_process_house_rewards() -> trigger
|
|
-- oid: 58431 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_process_house_rewards()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
WITH
|
|
task_player_contribution_threshold_passed (player_id, house_name, template_id, amount) AS (
|
|
SELECT NEW.player_id, tasks.house_name, task_rewards.template_id, task_rewards.amount
|
|
FROM landsraad_task_rewards as task_rewards
|
|
INNER JOIN landsraad_tasks AS tasks
|
|
ON task_rewards.task_id = tasks.id
|
|
LEFT JOIN landsraad_task_player_contributions AS player_contributions
|
|
ON player_contributions.task_id = tasks.id
|
|
WHERE task_rewards.task_id = NEW.task_id
|
|
AND tasks.id = NEW.task_id
|
|
AND player_contributions.player_id = NEW.player_id
|
|
AND COALESCE(OLD.amount, 0) < task_rewards.threshold
|
|
AND NEW.amount >= task_rewards.threshold)
|
|
INSERT INTO landsraad_house_rewards (player_id, house_name, template_id, amount, last_updated)
|
|
SELECT player_id, house_name, template_id, SUM(amount), CURRENT_TIMESTAMP FROM task_player_contribution_threshold_passed GROUP BY player_id, house_name, template_id
|
|
ON CONFLICT (player_id, house_name, template_id) DO UPDATE SET amount = landsraad_house_rewards.amount + excluded.amount, last_updated = CURRENT_TIMESTAMP;
|
|
|
|
RETURN NULL;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_process_task_progress(max_rows integer) -> void
|
|
-- oid: 58432 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_process_task_progress(max_rows integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
task_progress RECORD = NULL;
|
|
current_term_id BIGINT = NULL;
|
|
last_progress_id BIGINT = NULL;
|
|
old_processed_id BIGINT = NULL;
|
|
new_processed_id BIGINT = NULL;
|
|
new_amount INTEGER = 0;
|
|
player BIGINT = NULL;
|
|
guild BIGINT = NULL;
|
|
notify_guild_ids BIGINT[];
|
|
guild_ids_json JSON = NULL;
|
|
BEGIN
|
|
LOCK TABLE landsraad_task_progress_processed IN EXCLUSIVE MODE;
|
|
|
|
SELECT term_id FROM landsraad_decree_term ORDER BY start_time DESC LIMIT 1 INTO current_term_id;
|
|
|
|
SELECT id FROM landsraad_task_progress ORDER BY id DESC LIMIT 1 INTO last_progress_id;
|
|
|
|
SELECT last_processed_id FROM landsraad_task_progress_processed INTO old_processed_id;
|
|
|
|
-- read batch of rows sorted by id, process ordered by timestamp
|
|
FOR task_progress IN
|
|
WITH progress_batch AS (
|
|
SELECT landsraad_task_progress.id, landsraad_task_progress.faction_id, landsraad_task_progress.task_id,
|
|
landsraad_task_progress.faction_progress, landsraad_task_progress.guild_progress, landsraad_task_progress.player_progress, landsraad_task_progress.timestamp,
|
|
task_progress_players.players, task_progress_guilds.guilds
|
|
FROM landsraad_task_progress,
|
|
LATERAL (SELECT ARRAY_AGG(player_id) AS players FROM landsraad_task_progress_player WHERE landsraad_task_progress_player.progress_id = landsraad_task_progress.id) AS task_progress_players,
|
|
LATERAL (SELECT ARRAY_AGG(guild_id) AS guilds FROM landsraad_task_progress_guild WHERE landsraad_task_progress_guild.progress_id = landsraad_task_progress.id) AS task_progress_guilds
|
|
WHERE CASE WHEN old_processed_id IS NOT NULL THEN id > old_processed_id ELSE TRUE END
|
|
ORDER BY id LIMIT MAX_ROWS
|
|
)
|
|
SELECT id, faction_id, task_id, players, guilds, faction_progress, guild_progress, player_progress FROM progress_batch ORDER BY timestamp
|
|
LOOP
|
|
IF NOT (SELECT landsraad_has_term_of_task_ended(task_progress.task_id)) THEN
|
|
-- player progress is allowed to happen even if the task was already completed
|
|
IF task_progress.players IS NOT NULL THEN
|
|
FOREACH player IN ARRAY task_progress.players
|
|
LOOP
|
|
INSERT INTO landsraad_task_player_contributions AS player_contribution (player_id, faction_id, task_id, amount)
|
|
VALUES (player, task_progress.faction_id, task_progress.task_id, task_progress.player_progress)
|
|
ON CONFLICT (player_id, faction_id, task_id)
|
|
DO UPDATE SET amount = player_contribution.amount + task_progress.player_progress;
|
|
END LOOP;
|
|
END IF;
|
|
|
|
IF NOT (SELECT landsraad_task_has_been_completed(task_progress.task_id)) THEN
|
|
IF task_progress.guilds IS NOT NULL THEN
|
|
FOREACH guild IN ARRAY task_progress.guilds
|
|
LOOP
|
|
-- only insert to guild contribution if no vote has been placed
|
|
IF (SELECT NOT EXISTS (SELECT 1 FROM landsraad_decree_votes WHERE landsraad_decree_votes.guild_id = guild)) THEN
|
|
INSERT INTO landsraad_task_guild_contributions AS guild_contribution (guild_id, faction_id, task_id, amount)
|
|
VALUES (guild, task_progress.faction_id, task_progress.task_id, task_progress.guild_progress)
|
|
ON CONFLICT (guild_id, faction_id, task_id)
|
|
DO UPDATE SET amount = guild_contribution.amount + task_progress.guild_progress;
|
|
notify_guild_ids = notify_guild_ids || guild;
|
|
END IF;
|
|
|
|
END LOOP;
|
|
END IF;
|
|
|
|
INSERT INTO landsraad_task_faction_contributions AS faction_contribution (faction_id, task_id, amount)
|
|
VALUES (task_progress.faction_id, task_progress.task_id, task_progress.faction_progress)
|
|
ON CONFLICT (faction_id, task_id)
|
|
DO UPDATE SET amount = faction_contribution.amount + task_progress.faction_progress;
|
|
END IF;
|
|
END IF;
|
|
|
|
new_processed_id = task_progress.id;
|
|
END LOOP;
|
|
|
|
IF new_processed_id IS NOT NULL THEN
|
|
IF old_processed_id IS NULL THEN
|
|
INSERT INTO landsraad_task_progress_processed (last_processed_id) VALUES (new_processed_id);
|
|
ELSE
|
|
UPDATE landsraad_task_progress_processed SET last_processed_id = new_processed_id;
|
|
END IF;
|
|
END IF;
|
|
|
|
IF last_progress_id > new_processed_id THEN
|
|
PERFORM pg_notify('landsraad_notify_channel', format('progress_pressure#{"UnprocessedCount": %s}', last_progress_id - new_processed_id));
|
|
END IF;
|
|
|
|
IF new_processed_id > old_processed_id THEN
|
|
PERFORM pg_notify('landsraad_notify_channel', 'progress_updated#{"changed": true}');
|
|
ELSE
|
|
PERFORM pg_notify('landsraad_notify_channel', 'progress_updated#{"changed": false}');
|
|
END IF;
|
|
|
|
IF cardinality(notify_guild_ids) > 0 THEN
|
|
SELECT json_agg(DISTINCT guild_id) FROM (SELECT unnest(notify_guild_ids) guild_id) guilds INTO guild_ids_json;
|
|
PERFORM pg_notify('landsraad_notify_channel', format('guild_vote_changed#{"GuildIds": %s}', guild_ids_json));
|
|
END IF;
|
|
|
|
END $function$
|
|
|
|
|
|
-- landsraad_task_has_been_completed(in_task_id bigint) -> boolean
|
|
-- oid: 58433 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_task_has_been_completed(in_task_id bigint)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
task_completed BOOLEAN = FALSE;
|
|
BEGIN
|
|
SELECT task.completed FROM landsraad_tasks AS task WHERE task.id = in_task_id INTO task_completed;
|
|
RETURN task_completed;
|
|
END $function$
|
|
|
|
|
|
-- landsraad_update_decrees(IN in_decrees dune.landsraaddecree[]) -> void
|
|
-- oid: 58434 kind: PROCEDURE category: landsraad
|
|
|
|
CREATE OR REPLACE PROCEDURE dune.landsraad_update_decrees(IN in_decrees dune.landsraaddecree[])
|
|
LANGUAGE plpgsql
|
|
AS $procedure$
|
|
BEGIN
|
|
UPDATE landsraad_decrees SET disabled = TRUE WHERE decree_name NOT IN (
|
|
SELECT(UNNEST(in_decrees)).decree_name
|
|
);
|
|
INSERT INTO landsraad_decrees (decree_name, version, disabled, weight)
|
|
SELECT decrees.decree_name, decrees.version, decrees.disabled, decrees.weight FROM UNNEST(in_decrees) AS decrees
|
|
ON CONFLICT(decree_name) DO UPDATE SET version = excluded.version, disabled = excluded.disabled, weight = excluded.weight;
|
|
END $procedure$
|
|
|
|
|
|
-- landsraad_update_factions(IN in_faction_names text[]) -> void
|
|
-- oid: 58435 kind: PROCEDURE category: landsraad
|
|
|
|
CREATE OR REPLACE PROCEDURE dune.landsraad_update_factions(IN in_faction_names text[])
|
|
LANGUAGE plpgsql
|
|
AS $procedure$
|
|
BEGIN
|
|
WITH new_factions AS (
|
|
SELECT f FROM UNNEST(in_faction_names) f LEFT JOIN factions ON f = factions.name WHERE id IS NULL
|
|
)
|
|
INSERT INTO factions (name) SELECT * FROM new_factions;
|
|
END $procedure$
|
|
|
|
|
|
-- landsraad_update_task_faction_reveal_state(in_term_id bigint, in_task_board_index integer, faction_name text, reveal_state boolean) -> void
|
|
-- oid: 58436 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_update_task_faction_reveal_state(in_term_id bigint, in_task_board_index integer, faction_name text, reveal_state boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
taskid BIGINT = NULL;
|
|
factionid BIGINT = NULL;
|
|
BEGIN
|
|
SELECT id FROM landsraad_tasks tasks WHERE tasks.board_index = in_task_board_index AND tasks.term_id = in_term_id INTO taskid;
|
|
|
|
IF taskid IS NULL THEN
|
|
RAISE EXCEPTION 'Cannot update landsraad task reveal state, no task id for index % term %', in_task_board_index, in_term_id;
|
|
END IF;
|
|
|
|
SELECT id FROM factions WHERE factions.name = faction_name INTO factionid;
|
|
|
|
IF factionid IS NULL OR faction_name = 'None' THEN
|
|
RAISE EXCEPTION 'Cannot update landsraad task reveal state, invalid faction (%)', faction_name;
|
|
END IF;
|
|
|
|
INSERT INTO landsraad_task_reveal_state (task_id, faction_id, revealed, timestamp) VALUES (taskid, factionid, reveal_state, now()) ON CONFLICT(task_id, faction_id) DO UPDATE
|
|
SET revealed = reveal_state, timestamp = now();
|
|
|
|
PERFORM pg_notify('landsraad_notify_channel', 'progress_updated#{"changed": true}');
|
|
END $function$
|
|
|
|
|
|
-- landsraad_withdraw_house_reward(in_player_id bigint, in_house_rewards dune.landsraadplayerhousereward[]) -> void
|
|
-- oid: 58437 kind: FUNCTION category: landsraad
|
|
|
|
CREATE OR REPLACE FUNCTION dune.landsraad_withdraw_house_reward(in_player_id bigint, in_house_rewards dune.landsraadplayerhousereward[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
current_amount INTEGER = NULL;
|
|
house_reward record = NULL;
|
|
grouped_house_rewards LandsraadPlayerHouseReward[];
|
|
BEGIN
|
|
LOCK TABLE landsraad_house_rewards IN EXCLUSIVE MODE;
|
|
--group rewards to make sure multiple entries of the same item do not slip by amount verfication below
|
|
WITH grouped_rewards AS (SELECT house_name, template_id, SUM(amount) as amount FROM UNNEST(in_house_rewards) GROUP BY house_name, template_id)
|
|
SELECT ARRAY_AGG((grouped_rewards.house_name, grouped_rewards.template_id, grouped_rewards.amount)::LandsraadPlayerHouseReward) INTO grouped_house_rewards FROM grouped_rewards;
|
|
|
|
FOREACH house_reward in ARRAY grouped_house_rewards
|
|
LOOP
|
|
SELECT lhr.amount INTO current_amount FROM landsraad_house_rewards AS lhr WHERE lhr.player_id = in_player_id AND lhr.house_name = house_reward.house_name AND lhr.template_id = house_reward.template_id;
|
|
|
|
IF current_amount IS NULL OR current_amount < house_reward.amount THEN
|
|
RAISE EXCEPTION 'Cannot withdraw house reward %s for player % and house %s', house_reward.template_id, in_player_id, house_reward.house_name;
|
|
RETURN;
|
|
END IF;
|
|
END LOOP;
|
|
-- finish full loop of checks first, all rewards need to be withdrawable before updating
|
|
FOREACH house_reward in ARRAY grouped_house_rewards
|
|
LOOP
|
|
UPDATE landsraad_house_rewards SET amount = amount - house_reward.amount, last_updated = CURRENT_TIMESTAMP WHERE player_id = in_player_id AND house_name = house_reward.house_name AND template_id = house_reward.template_id;
|
|
END LOOP;
|
|
END $function$
|
|
|
|
|
|
-- load_actors(in_actor_ids bigint[], in_actor_state dune.actorstate) -> TABLE(ord bigint, actor_id bigint, generic_data dune.actorgenericdata, serial bigint)
|
|
-- oid: 58438 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_actors(in_actor_ids bigint[], in_actor_state dune.actorstate DEFAULT 'Default'::dune.actorstate)
|
|
RETURNS TABLE(ord bigint, actor_id bigint, generic_data dune.actorgenericdata, serial bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
with
|
|
ids as (
|
|
select * from unnest(in_actor_ids) with ordinality as t(id, ord)
|
|
),
|
|
entities as (
|
|
select
|
|
fgl_bridge.actor_id,
|
|
(fgl_bridge.entity_id, fgl_bridge.slot_name, entity_data.components)::FglEntity as data
|
|
from
|
|
ids
|
|
left join actor_fgl_entities as fgl_bridge on ids.id=fgl_bridge.actor_id
|
|
left join fgl_entities as entity_data on fgl_bridge.entity_id = entity_data.entity_id
|
|
)
|
|
select
|
|
ids.ord, actors.id,
|
|
(
|
|
coalesce(array_agg(entities.data) filter (where entities.data is not null), array[]::FglEntity[]),
|
|
actors.properties,
|
|
actors.gas_attributes,
|
|
case
|
|
when exists(select 1 from buildings where actors.id = buildings.id) then load_building(actors.id)
|
|
end
|
|
,
|
|
case
|
|
when exists(select 1 from placeables where actors.id = placeables.id) then load_placeable(actors.id)
|
|
end
|
|
,
|
|
case
|
|
when exists(select 1 from totems where actors.id = totems.id) then load_totem(actors.id)
|
|
end
|
|
)::ActorGenericData, actors.serial
|
|
from
|
|
ids
|
|
join actors using (id)
|
|
left join entities on actors.id = entities.actor_id
|
|
where
|
|
case when (in_actor_state = 'Default') then
|
|
not exists(select 1 from actor_state where actors.id = actor_state.actor_id)
|
|
else
|
|
exists(select 1 from actor_state where actors.id = actor_state.actor_id and actor_state.state = in_actor_state)
|
|
end
|
|
group by ids.ord, actors.id, actors.properties, actors.gas_attributes, actors.serial
|
|
order by ids.ord;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- load_backup_vehicle(in_account_id bigint) -> TABLE(out_id bigint, out_class text, out_customization_id text)
|
|
-- oid: 58439 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_backup_vehicle(in_account_id bigint)
|
|
RETURNS TABLE(out_id bigint, out_class text, out_customization_id text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT a.id, a.class, bv.customization_id
|
|
FROM actors a
|
|
JOIN backup_vehicles bv on a.id = bv.vehicle_id
|
|
WHERE bv.account_id = in_account_id
|
|
LIMIT 1;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- load_building(in_building_id bigint) -> dune.buildingsavedata
|
|
-- oid: 58449 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_building(in_building_id bigint)
|
|
RETURNS dune.buildingsavedata
|
|
LANGUAGE sql
|
|
BEGIN ATOMIC
|
|
RETURN ( SELECT ROW(array_agg(ROW(building_instances.instance_id, building_instances.building_type, building_instances.transform, building_instances.owner_entity_id, building_instances.building_flags, building_instances.health, building_instances.shelter, building_instances.stabilization_begin_timespan, building_instances.stabilization_end_timespan, building_instances.stabilization_state, building_instances.sand_buildup)::dune.buildinginstance), ARRAY[]::integer[], ARRAY[]::dune.buildinginstanceupdateowner[], ARRAY[]::dune.buildinginstanceupdatestabilization[], ARRAY[]::dune.buildinginstanceupdatehealth[], ARRAY[]::dune.buildinginstanceupdateshelter[], ARRAY[]::dune.buildinginstanceupdatesandbuildup[], ARRAY[]::dune.buildinginstanceupdatebuildingflags[], ARRAY[]::dune.buildinginstanceupdatetransform[])::dune.buildingsavedata AS "row"
|
|
FROM dune.building_instances
|
|
WHERE (building_instances.building_id = load_building.in_building_id));
|
|
END
|
|
|
|
|
|
-- load_communinet_player_data(in_account_id bigint) -> TABLE(is_active boolean, selected_channel_name text, channel_name text, is_tuned boolean)
|
|
-- oid: 58450 kind: FUNCTION category: communinet
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_communinet_player_data(in_account_id bigint)
|
|
RETURNS TABLE(is_active boolean, selected_channel_name text, channel_name text, is_tuned boolean)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT cp.is_active, cp.selected_channel_name, cpc.channel_name, cpc.is_tuned
|
|
FROM communinet_player AS cp JOIN communinet_player_channels as cpc
|
|
ON cp.account_id = cpc.account_id
|
|
WHERE cpc.account_id = in_account_id;
|
|
END; $function$
|
|
|
|
|
|
-- load_dialogue_data(in_player_controller_id bigint, OUT met_npcs text[], OUT taken_nodes integer[]) -> record
|
|
-- oid: 58451 kind: FUNCTION category: dialogue
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_dialogue_data(in_player_controller_id bigint, OUT met_npcs text[], OUT taken_nodes integer[])
|
|
RETURNS record
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
SELECT ARRAY_AGG(npc_name)
|
|
INTO met_npcs
|
|
FROM dialogue_met_npcs
|
|
WHERE player_id = in_player_controller_id;
|
|
|
|
SELECT ARRAY_AGG(node_id)
|
|
INTO taken_nodes
|
|
FROM dialogue_taken_nodes
|
|
WHERE player_id = in_player_controller_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- load_dimension_index(in_map text, in_partition_id bigint) -> integer
|
|
-- oid: 58452 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_dimension_index(in_map text, in_partition_id bigint)
|
|
RETURNS integer
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN (SELECT dimension_index from world_partition where map = in_map and partition_id = in_partition_id limit 1);
|
|
END; $function$
|
|
|
|
|
|
-- load_events_log_data_from_player(in_actor_id bigint, in_limit_entries_num integer) -> TABLE(game_event_owner bigint, universe_time timestamp without time zone, map_name text, partition_id bigint, event_type integer, x_location double precision, y_location double precision, z_location double precision, custom_data jsonb)
|
|
-- oid: 58453 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_events_log_data_from_player(in_actor_id bigint, in_limit_entries_num integer)
|
|
RETURNS TABLE(game_event_owner bigint, universe_time timestamp without time zone, map_name text, partition_id bigint, event_type integer, x_location double precision, y_location double precision, z_location double precision, custom_data jsonb)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT temp.actor_id, (temp.universe_time AT TIME ZONE 'UTC')::TIMESTAMP, temp.map, temp.partition_id, temp.event_type, temp.x, temp.y, temp.z, temp.custom_data
|
|
FROM (SELECT game_events.actor_id, game_events.universe_time, game_events.map, game_events.partition_id, game_events.event_type, game_events.x, game_events.y, game_events.z, game_events.custom_data FROM game_events WHERE game_events.actor_id = in_actor_id AND game_events.player_facing_event = true ORDER BY game_events.universe_time DESC LIMIT in_limit_entries_num) temp
|
|
ORDER BY temp.universe_time ASC;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- load_full_actors(in_ids bigint[]) -> SETOF dune.actordescription
|
|
-- oid: 58454 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_full_actors(in_ids bigint[])
|
|
RETURNS SETOF dune.actordescription
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
with
|
|
ids as (
|
|
select * from unnest(in_ids) with ordinality as t(id, ord)
|
|
),
|
|
entities as (
|
|
select
|
|
actor_id,
|
|
(fgl_bridge.entity_id, fgl_bridge.slot_name, entity_data.components)::FglEntity as data
|
|
from
|
|
ids
|
|
left join actor_fgl_entities as fgl_bridge on ids.id=fgl_bridge.actor_id
|
|
left join fgl_entities as entity_data using (entity_id)
|
|
)
|
|
select
|
|
id, "class", "transform", (
|
|
coalesce(array_agg(entities.data) filter (where entities.data is not null), array[]::FglEntity[]),
|
|
actors.properties,
|
|
actors.gas_attributes,
|
|
case
|
|
when exists(select 1 from buildings where ids.id = buildings.id) then load_building(id)
|
|
else null
|
|
end,
|
|
case
|
|
when exists(select 1 from placeables where ids.id = placeables.id) then load_placeable(id)
|
|
else null
|
|
end
|
|
,
|
|
case
|
|
when exists(select 1 from totems where id = totems.id) then load_totem(id)
|
|
end
|
|
)::ActorGenericData, actors.serial
|
|
from
|
|
ids
|
|
join actors using (id)
|
|
left join entities on id=entities.actor_id
|
|
group by ids.ord, id, class, "transform", actors.properties, actors.gas_attributes, actors.serial
|
|
order by ids.ord;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- load_item(in_item_id bigint) -> TABLE(item_id bigint, stack_size bigint, quality_level bigint, volume_override real, position_index bigint, template_id text, inventory_id bigint, is_new boolean, acquisition_time bigint, stats jsonb, sub_inventory_id bigint)
|
|
-- oid: 58455 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_item(in_item_id bigint)
|
|
RETURNS TABLE(item_id bigint, stack_size bigint, quality_level bigint, volume_override real, position_index bigint, template_id text, inventory_id bigint, is_new boolean, acquisition_time bigint, stats jsonb, sub_inventory_id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT item.id, item.stack_size, item.quality_level, item.volume_override, item.position_index, item.template_id, item.inventory_id, item.is_new, item.acquisition_time, item.stats, inventory.id
|
|
FROM items item
|
|
LEFT JOIN inventories inventory ON (inventory.item_id = item.id)
|
|
WHERE item.id = in_item_id;
|
|
END; $function$
|
|
|
|
|
|
-- load_items(in_inventory_id bigint) -> TABLE(item_id bigint, stack_size bigint, quality_level bigint, volume_override real, position_index bigint, template_id text, inventory_id bigint, is_new boolean, acquisition_time bigint, stats jsonb, sub_inventory_id bigint)
|
|
-- oid: 58456 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_items(in_inventory_id bigint)
|
|
RETURNS TABLE(item_id bigint, stack_size bigint, quality_level bigint, volume_override real, position_index bigint, template_id text, inventory_id bigint, is_new boolean, acquisition_time bigint, stats jsonb, sub_inventory_id bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
WITH RECURSIVE items_cte AS (
|
|
SELECT item.id, item.stack_size, item.quality_level, item.volume_override, item.position_index, item.template_id, item.inventory_id, item.is_new, item.acquisition_time, item.stats, inventory.id as sub_inventory_id
|
|
FROM items item
|
|
LEFT JOIN inventories inventory ON (inventory.item_id = item.id)
|
|
WHERE item.inventory_id = in_inventory_id
|
|
UNION ALL
|
|
SELECT item.id, item.stack_size, item.quality_level, item.volume_override, item.position_index, item.template_id, item.inventory_id, item.is_new, item.acquisition_time, item.stats, inventory.id as sub_inventory_id
|
|
FROM items item
|
|
LEFT JOIN inventories inventory ON (inventory.item_id = item.id)
|
|
JOIN items_cte ON item.inventory_id = items_cte.sub_inventory_id
|
|
WHERE items_cte.sub_inventory_id IS NOT NULL
|
|
)
|
|
SELECT * FROM items_cte order by id asc;
|
|
END; $function$
|
|
|
|
|
|
-- load_map_areas_entries(in_account_id bigint, in_map_name text) -> TABLE(account_id bigint, area_id smallint, time_discovered timestamp without time zone, time_first_entered timestamp without time zone, survey_point_marker_id bigint, items_surveyed_target jsonb, items_surveyed_progress jsonb, map_name text)
|
|
-- oid: 58457 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_map_areas_entries(in_account_id bigint, in_map_name text)
|
|
RETURNS TABLE(account_id bigint, area_id smallint, time_discovered timestamp without time zone, time_first_entered timestamp without time zone, survey_point_marker_id bigint, items_surveyed_target jsonb, items_surveyed_progress jsonb, map_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT
|
|
map_areas.account_id,
|
|
map_areas.area_id,
|
|
map_areas.time_discovered AT TIME ZONE 'UTC',
|
|
map_areas.time_first_entered AT TIME ZONE 'UTC',
|
|
map_areas.survey_point_marker_id,
|
|
map_areas.items_surveyed_target,
|
|
map_areas.items_surveyed_progress,
|
|
map_areas.map_name
|
|
from map_areas WHERE map_areas.account_id = in_account_id AND map_areas.map_name = in_map_name;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- load_markers(in_player_id bigint, in_dimension_id integer, in_map_name text) -> TABLE(out_marker_hash_id integer, out_marker_type text, out_x double precision, out_y double precision, out_z double precision, out_payload_type text, out_area_id smallint, out_area_radius real, out_long_range boolean, out_payload jsonb, out_discovery_level smallint, out_discovery_method smallint, out_player_payload jsonb)
|
|
-- oid: 58458 kind: FUNCTION category: markers
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_markers(in_player_id bigint, in_dimension_id integer, in_map_name text)
|
|
RETURNS TABLE(out_marker_hash_id integer, out_marker_type text, out_x double precision, out_y double precision, out_z double precision, out_payload_type text, out_area_id smallint, out_area_radius real, out_long_range boolean, out_payload jsonb, out_discovery_level smallint, out_discovery_method smallint, out_player_payload jsonb)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT
|
|
player_markers.marker_hash_id,
|
|
(markers.marker).marker_type,
|
|
(markers.marker).x,
|
|
(markers.marker).y,
|
|
(markers.marker).z,
|
|
(markers.marker).payload_type,
|
|
area_id,
|
|
area_radius,
|
|
long_range,
|
|
markers.payload,
|
|
discovery_level,
|
|
discovery_method,
|
|
player_markers.payload
|
|
FROM map_names JOIN markers ON markers.map_name_id = map_names.map_name_id
|
|
JOIN player_markers ON markers.marker_hash_id = player_markers.marker_hash_id
|
|
AND markers.dimension_index = player_markers.dimension_index
|
|
AND markers.map_name_id = player_markers.map_name_id
|
|
WHERE player_markers.player_id = in_player_id
|
|
AND (player_markers.dimension_index = in_dimension_id OR player_markers.dimension_index = -1)
|
|
AND map_names.map_name = in_map_name;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- load_partition_definition_map() -> TABLE(out_partition_id bigint, out_server_id text, out_partition_definition jsonb, out_dimension_index integer, out_blocked boolean, out_label text, out_map text)
|
|
-- oid: 58459 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_partition_definition_map()
|
|
RETURNS TABLE(out_partition_id bigint, out_server_id text, out_partition_definition jsonb, out_dimension_index integer, out_blocked boolean, out_label text, out_map text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT wp.partition_id, active_server_ids.server_id AS server_id, wp.partition_definition,
|
|
wp.dimension_index, wp.blocked, wp.label, wp.map
|
|
FROM world_partition as wp
|
|
LEFT JOIN active_server_ids
|
|
ON active_server_ids.server_id = wp.server_id;
|
|
END; $function$
|
|
|
|
|
|
-- load_placeable(in_placeable_id bigint) -> dune.placeablesavedata
|
|
-- oid: 58460 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_placeable(in_placeable_id bigint)
|
|
RETURNS dune.placeablesavedata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result PlaceableSaveData;
|
|
BEGIN
|
|
SELECT
|
|
owner_entity_id as in_owner_entity_id,
|
|
health as in_health,
|
|
building_type as in_building_type,
|
|
has_hit_ground as in_has_hit_ground,
|
|
has_buildable_support as in_has_buildable_support,
|
|
is_hologram as in_is_hologram
|
|
INTO result
|
|
FROM placeables
|
|
WHERE id = in_placeable_id;
|
|
return result;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- load_recovered_vehicles(in_account_id bigint, in_restore_time_limit integer) -> TABLE(out_vehicle_id bigint, out_class text, out_name text, out_time_stored timestamp without time zone, out_chassis_durability real, out_customization_id text, out_migrated boolean)
|
|
-- oid: 58461 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_recovered_vehicles(in_account_id bigint, in_restore_time_limit integer)
|
|
RETURNS TABLE(out_vehicle_id bigint, out_class text, out_name text, out_time_stored timestamp without time zone, out_chassis_durability real, out_customization_id text, out_migrated boolean)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT vehicle_id, class, vehicle_name, time_stored AT TIME ZONE 'UTC', chassis_durability, customization_id, migrated
|
|
FROM actors
|
|
JOIN recovered_vehicles on id = vehicle_id
|
|
WHERE account_id = in_account_id
|
|
AND (migrated = TRUE OR time_stored > NOW() - in_restore_time_limit * INTERVAL '1 second')
|
|
AND EXISTS (SELECT 1 FROM actor_state WHERE actor_state.actor_id = id AND actor_state.state = 'VehicleRecovery')
|
|
ORDER BY time_stored DESC;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- load_static_encounter_name(in_map_name text, in_package_name text, in_actor_name text) -> TABLE(encounter_name text, waiting_for_reset boolean)
|
|
-- oid: 58462 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_static_encounter_name(in_map_name text, in_package_name text, in_actor_name text)
|
|
RETURNS TABLE(encounter_name text, waiting_for_reset boolean)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT t.encounter_name, t.waiting_for_reset
|
|
FROM encounters_static as t
|
|
WHERE t.map_name = in_map_name AND t.package_name = in_package_name AND t.actor_name = in_actor_name;
|
|
END; $function$
|
|
|
|
|
|
-- load_takeoverable_user_ids() -> SETOF dune.takeovercharacterdatacomposite
|
|
-- oid: 58463 kind: FUNCTION category: takeover
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_takeoverable_user_ids()
|
|
RETURNS SETOF dune.takeovercharacterdatacomposite
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT acc.user, ps.character_name
|
|
FROM accounts acc LEFT JOIN player_state ps ON acc.id=ps.account_id
|
|
WHERE acc.takeoverable=true;
|
|
END; $function$
|
|
|
|
|
|
-- load_totem(in_id bigint) -> dune.totemsavedata
|
|
-- oid: 58464 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_totem(in_id bigint)
|
|
RETURNS dune.totemsavedata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
result TotemSaveData;
|
|
BEGIN
|
|
SELECT
|
|
landclaim_vertical_level,
|
|
last_backup_timestamp,
|
|
landclaim_original_global_location,
|
|
landclaim_original_global_yaw_rotation
|
|
INTO result
|
|
FROM totems
|
|
WHERE id = in_id;
|
|
return result;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- load_travel_return_info(in_player_controller_id bigint) -> TABLE(map text, transform dune.transform)
|
|
-- oid: 58465 kind: FUNCTION category: travel
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_travel_return_info(in_player_controller_id bigint)
|
|
RETURNS TABLE(map text, transform dune.transform)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
select travel_return_info.map, travel_return_info.transform
|
|
from travel_return_info
|
|
where player_controller_id = in_player_controller_id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- load_travel_to_player_info(in_player_controller_id bigint) -> TABLE(map text, transform dune.transform, partition_id bigint, dimension_index integer)
|
|
-- oid: 58466 kind: FUNCTION category: travel
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_travel_to_player_info(in_player_controller_id bigint)
|
|
RETURNS TABLE(map text, transform dune.transform, partition_id bigint, dimension_index integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
select actors.map, actors.transform, actors.partition_id, actors.dimension_index
|
|
from player_state
|
|
join actors on player_state.player_pawn_id = actors.id
|
|
where player_state.player_controller_id = in_player_controller_id
|
|
and player_state.online_status = 'Online';
|
|
end
|
|
$function$
|
|
|
|
|
|
-- load_vehicle_modules(in_vehicle_id bigint) -> TABLE(module_id bigint, template_id text, stats jsonb)
|
|
-- oid: 58467 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_vehicle_modules(in_vehicle_id bigint)
|
|
RETURNS TABLE(module_id bigint, template_id text, stats jsonb)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query SELECT vm.id, vm.template_id, vm.stats FROM vehicle_modules vm WHERE vehicle_id = in_vehicle_id ORDER BY id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- load_world_partition(in_map_name text, in_server_id text, in_desired_dimension_index bigint, in_desired_partition_id bigint) -> TABLE(partition_id bigint, partition_definition jsonb, dimension_index integer, blocked boolean, label text)
|
|
-- oid: 58468 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.load_world_partition(in_map_name text, in_server_id text, in_desired_dimension_index bigint DEFAULT 0, in_desired_partition_id bigint DEFAULT NULL::bigint)
|
|
RETURNS TABLE(partition_id bigint, partition_definition jsonb, dimension_index integer, blocked boolean, label text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
tmp_partition RECORD;
|
|
BEGIN
|
|
-- First check if the server already have a partition assigned
|
|
SELECT INTO tmp_partition wp.partition_id, wp.partition_definition, wp.dimension_index, wp.blocked, wp.label
|
|
FROM world_partition wp
|
|
WHERE server_id = in_server_id AND wp.map = in_map_name AND wp.dimension_index = in_desired_dimension_index;
|
|
IF tmp_partition.partition_id IS NOT NULL THEN
|
|
RETURN QUERY SELECT tmp_partition.partition_id, tmp_partition.partition_definition, tmp_partition.dimension_index, tmp_partition.blocked, tmp_partition.label;
|
|
RETURN;
|
|
END IF;
|
|
|
|
-- No partition assigned, so try to find an unassigned partition for this server
|
|
SELECT INTO tmp_partition wp.partition_id, wp.partition_definition, wp.dimension_index, wp.blocked, wp.label
|
|
FROM world_partition wp
|
|
WHERE (server_id IS NULL OR server_id NOT IN (SELECT * FROM active_server_ids)) AND wp.map = in_map_name AND wp.dimension_index = in_desired_dimension_index
|
|
ORDER BY (wp.partition_id = in_desired_partition_id) DESC, wp.partition_definition->'type', wp.partition_definition->'index', wp.partition_definition->'box'->'min_x', wp.partition_definition->'box'->'min_y'
|
|
LIMIT 1
|
|
FOR UPDATE SKIP LOCKED;
|
|
IF tmp_partition.partition_id IS NULL THEN
|
|
RETURN;
|
|
ELSE
|
|
-- Fake a server
|
|
INSERT INTO farm_state(server_id, farm_id, outgoing_s2s_connections, incoming_s2s_connections, connected_players, igw_addr, igw_port, game_addr, game_port, map, revision)
|
|
VALUES (in_server_id, '0', 0, 0, 0, '0.0.0.0', 0, '0.0.0.0', 0, '', 0) ON CONFLICT DO NOTHING;
|
|
UPDATE world_partition SET server_id = in_server_id WHERE world_partition.partition_id = tmp_partition.partition_id;
|
|
NOTIFY world_partition_update;
|
|
RETURN QUERY SELECT tmp_partition.partition_id, tmp_partition.partition_definition, tmp_partition.dimension_index, tmp_partition.blocked, tmp_partition.label;
|
|
RETURN;
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- log_cheating(in_fls_id text, in_cheat_type dune.cheat_type_enum, in_event_time timestamp with time zone) -> void
|
|
-- oid: 58469 kind: FUNCTION category: anticheat
|
|
|
|
CREATE OR REPLACE FUNCTION dune.log_cheating(in_fls_id text, in_cheat_type dune.cheat_type_enum, in_event_time timestamp with time zone DEFAULT now())
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
|
|
-- Insert into suspicious_be
|
|
INSERT INTO cheater_tracking (
|
|
event_time,
|
|
fls_id,
|
|
cheat_type
|
|
) VALUES (
|
|
in_event_time,
|
|
in_fls_id,
|
|
in_cheat_type
|
|
);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- log_event_solaris(in_function_oid oid, in_message dune.logmessagetype, in_controller_id bigint, in_solaris_balance bigint, in_solaris_delta bigint) -> void
|
|
-- oid: 58470 kind: FUNCTION category: currency
|
|
|
|
CREATE OR REPLACE FUNCTION dune.log_event_solaris(in_function_oid oid, in_message dune.logmessagetype, in_controller_id bigint, in_solaris_balance bigint, in_solaris_delta bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
partition_id BIGINT = 0;
|
|
calling_function_name LogFunctionType;
|
|
fls_id TEXT;
|
|
fc_id BYTEA;
|
|
char_name BYTEA;
|
|
BEGIN
|
|
|
|
partition_id := coalesce(current_setting('dune.partition_id', true)::BIGINT, 0);
|
|
|
|
-- map calling function name to LogFunctionType (each calling function must be added to LogFunctionType)
|
|
SELECT proname::text::LogFunctionType
|
|
INTO calling_function_name
|
|
FROM pg_proc
|
|
WHERE oid = in_function_oid;
|
|
|
|
-- get the fls_id for the user performing the acction
|
|
SELECT acc."user"
|
|
INTO fls_id
|
|
FROM accounts acc
|
|
JOIN player_state ps on ps.account_id = acc.id
|
|
WHERE ps.player_controller_id = in_controller_id
|
|
LIMIT 1;
|
|
|
|
INSERT INTO event_log (
|
|
partition_id,
|
|
category,
|
|
function_name,
|
|
message,
|
|
event_time,
|
|
meta
|
|
) VALUES (
|
|
partition_id,
|
|
'solaris',
|
|
calling_function_name,
|
|
in_message,
|
|
now(),
|
|
json_build_object('fls_id', fls_id, 'event', calling_function_name::text, 'solaris_balance', in_solaris_balance, 'solaris_delta', in_solaris_delta)
|
|
);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- login_account(in_user_id text, in_funcom_id text, in_platform_id text, in_platform_name text, in_minimum_returning_player_time_seconds integer, in_character_name text, in_return_dimension_index integer, in_home_dimension_index integer) -> SETOF dune.playerdescription
|
|
-- oid: 58471 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.login_account(in_user_id text, in_funcom_id text, in_platform_id text, in_platform_name text, in_minimum_returning_player_time_seconds integer, in_character_name text, in_return_dimension_index integer, in_home_dimension_index integer)
|
|
RETURNS SETOF dune.playerdescription
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
user_account_id BigInt;
|
|
BEGIN
|
|
PERFORM update_returning_player_status(in_user_id, in_minimum_returning_player_time_seconds);
|
|
|
|
return query with
|
|
acc as (
|
|
INSERT INTO encrypted_accounts("id", "user", "platform_id", "platform_name", "encrypted_funcom_id")
|
|
VALUES (default, in_user_id, in_platform_id, in_platform_name, encrypt_user_data(in_funcom_id))
|
|
ON CONFLICT ("user") DO UPDATE SET
|
|
encrypted_funcom_id = excluded.encrypted_funcom_id,
|
|
platform_id = excluded.platform_id,
|
|
platform_name = excluded.platform_name
|
|
RETURNING id, encrypted_accounts.user
|
|
),
|
|
actor_ids as (
|
|
-- TODO: unite this with accounts. One table to rule them all (until we want multiple chars per account)
|
|
SELECT
|
|
coalesce(player_controller_id, nextval('actors_id_seq')) as controller,
|
|
coalesce(player_state_id, nextval('actors_id_seq')) as state,
|
|
coalesce(player_pawn_id, nextval('actors_id_seq')) as pawn
|
|
from acc left join player_state on player_state.account_id = acc.id
|
|
),
|
|
actors_insert as (
|
|
INSERT INTO actors("id", "owner_account_id")
|
|
select unnest(array[controller, pawn, state]), acc.id from actor_ids, acc
|
|
ON CONFLICT DO NOTHING
|
|
returning id
|
|
),
|
|
insert_actor_audit_log as (
|
|
insert into actor_audit("id", "class")
|
|
select
|
|
unnest(array[controller, pawn, state]) as id,
|
|
unnest(array['Controller', 'Pawn', 'State']) as clas
|
|
from actor_ids
|
|
on conflict do nothing
|
|
),
|
|
demo as (
|
|
UPDATE demo_users
|
|
SET demo_state = CASE
|
|
WHEN demo_playtime_seconds IS NOT NULL THEN 'Demo'::DemoState
|
|
ELSE demo_state
|
|
END
|
|
WHERE fls_id = in_user_id
|
|
RETURNING fls_id, demo_playtime_seconds, demo_state
|
|
),
|
|
player_state_insert as (
|
|
INSERT INTO encrypted_player_state(
|
|
"account_id", "encrypted_character_name", "online_status",
|
|
"player_controller_id", "player_pawn_id", "player_state_id",
|
|
"return_dimension_index", "home_dimension_index", "last_login_time"
|
|
)
|
|
select
|
|
id, case
|
|
when in_character_name is not null then encrypt_user_data(in_character_name)
|
|
when encrypted_player_state.encrypted_character_name is null then encrypt_user_data('<TEMP>')
|
|
else encrypted_player_state.encrypted_character_name
|
|
end,
|
|
'Online', controller, pawn, state, in_return_dimension_index, in_home_dimension_index, now()
|
|
from acc left join encrypted_player_state on acc.id = encrypted_player_state.account_id, actor_ids
|
|
ON CONFLICT ("account_id")
|
|
DO UPDATE SET
|
|
online_status = 'Online',
|
|
"return_dimension_index" = coalesce(in_return_dimension_index, encrypted_player_state.return_dimension_index),
|
|
"home_dimension_index" = coalesce(in_home_dimension_index, encrypted_player_state.home_dimension_index),
|
|
"last_login_time" = now()
|
|
RETURNING
|
|
account_id,
|
|
"return_dimension_index",
|
|
"home_dimension_index"
|
|
),
|
|
inserted_count_dummy as (
|
|
select count(*) from actors_insert
|
|
),
|
|
player_actors as (
|
|
select array_agg(full_actors.*) as actors
|
|
from
|
|
-- We need to refer 'returning' from inserts to ensure order of with statements
|
|
inserted_count_dummy,
|
|
actor_ids,
|
|
load_full_actors(array[actor_ids.controller, actor_ids.state, actor_ids.pawn]) as full_actors
|
|
),
|
|
pawn_info as (
|
|
select id, (map, partition_id, dimension_index)::ServerInfo as server_info
|
|
from actor_ids join actors on actors.id=actor_ids.pawn
|
|
),
|
|
respawn_locations as (
|
|
SELECT acc.id as account_id, get_respawn_locations(acc.id) as locations
|
|
FROM acc
|
|
),
|
|
this_player_tags as (
|
|
select
|
|
acc.id as account_id,
|
|
array_agg(tag) as tags
|
|
from acc join player_tags as tgs on tgs.account_id=acc.id
|
|
group by acc.id
|
|
),
|
|
keystones as (
|
|
select player_id, array_agg(keystone_id) as purchased_keystones
|
|
from purchased_specialization_keystones
|
|
group by player_id
|
|
),
|
|
tracks as (
|
|
select player_id, array_agg(track_info) as progression_tracks
|
|
from (
|
|
select player_id, (track_type, xp_amount, level)::SpecializationTrackInfo as track_info
|
|
from specialization_tracks
|
|
)
|
|
group by player_id
|
|
),
|
|
journey_nodes as (
|
|
SELECT acc.id as account_id, get_login_journey_nodes(acc.id) as journey_nodes_data
|
|
FROM acc
|
|
),
|
|
journey_nodes_cooldown as (
|
|
SELECT acc.id as account_id, get_login_journey_nodes_cooldown(acc.id) as journey_nodes_cooldown_data
|
|
FROM acc
|
|
)
|
|
select
|
|
acc.id,
|
|
player_actors.actors[1], player_actors.actors[2], player_actors.actors[3],
|
|
coalesce(pawn_info.server_info, (null, null, null)::ServerInfo),
|
|
(
|
|
coalesce(respawn_locations.locations, array[]::RespawnLocation[]),
|
|
player_state.pending_respawn_location_id
|
|
)::RespawnInfo,
|
|
coalesce(player_state.life_state, 'Alive'),
|
|
coalesce(this_player_tags.tags, array[]::Text[]),
|
|
player_state_insert.return_dimension_index,
|
|
player_state.death_location,
|
|
player_state_insert.home_dimension_index,
|
|
demo.demo_state,
|
|
demo.demo_playtime_seconds,
|
|
(progression_tracks, purchased_keystones, refund_id)::SpecializationInfo,
|
|
(
|
|
coalesce(journey_nodes.journey_nodes_data, array[]::JourneyNodeInfo[]),
|
|
coalesce(journey_nodes_cooldown.journey_nodes_cooldown_data, array[]::JourneyNodeCooldownInfo[]),
|
|
coalesce(journey_tracked_cards.tracked_journey_card, ''),
|
|
coalesce(journey_tracked_cards.tracked_landsraad_card, '')
|
|
)::JourneyInfo,
|
|
(player_state.last_returning_player_event_time AT TIME ZONE 'UTC')::TIMESTAMP,
|
|
(player_state.last_returning_player_awarded_time AT TIME ZONE 'UTC')::TIMESTAMP
|
|
from
|
|
acc left join player_state on player_state.account_id = acc.id
|
|
left join respawn_locations on respawn_locations.account_id = acc.id
|
|
left join this_player_tags on this_player_tags.account_id = acc.id
|
|
left join player_state_insert on player_state_insert.account_id = acc.id
|
|
left join demo on demo.fls_id = acc.user
|
|
left join journey_nodes on journey_nodes.account_id = acc.id
|
|
left join journey_nodes_cooldown on journey_nodes_cooldown.account_id = acc.id
|
|
left join journey_tracked_cards on journey_tracked_cards.player_id = player_state.player_controller_id
|
|
left join keystones on keystones.player_id = player_state.player_controller_id
|
|
left join tracks on tracks.player_id = player_state.player_controller_id
|
|
left join specialization_refund_id on specialization_refund_id.player_id = player_state.player_controller_id,
|
|
|
|
player_actors left join pawn_info on (player_actors.actors[3].id = pawn_info.id)
|
|
limit 1;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- mark_server_dead(in_server_id text) -> void
|
|
-- oid: 58473 kind: FUNCTION category: server
|
|
|
|
CREATE OR REPLACE FUNCTION dune.mark_server_dead(in_server_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE farm_state SET alive = false WHERE server_id = in_server_id;
|
|
END $function$
|
|
|
|
|
|
-- merge_inventory_items(in_item_id bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint) -> bigint
|
|
-- oid: 58474 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.merge_inventory_items(in_item_id bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
remaining_stack_size BIGINT;
|
|
item_data items%ROWTYPE;
|
|
dst_item_data items%ROWTYPE;
|
|
BEGIN
|
|
SELECT INTO STRICT item_data * FROM items WHERE id = in_item_id;
|
|
|
|
SELECT INTO dst_item_data * FROM items WHERE inventory_id = in_dst_inventory_id AND position_index = in_dst_index;
|
|
|
|
IF dst_item_data.id IS NULL THEN
|
|
RETURN NULL;
|
|
END IF;
|
|
|
|
remaining_stack_size := item_data.stack_size - in_count;
|
|
|
|
IF remaining_stack_size < 0 THEN
|
|
RETURN NULL;
|
|
END IF;
|
|
|
|
|
|
IF item_data.template_id != dst_item_data.template_id THEN
|
|
RETURN NULL;
|
|
END IF;
|
|
|
|
-- log item tracking
|
|
PERFORM _add_item_trace_log('merge_inventory_items', in_item_id, in_dst_inventory_id, NULL, in_dst_index);
|
|
|
|
IF remaining_stack_size > 0 THEN
|
|
UPDATE items SET stack_size = remaining_stack_size WHERE id = in_item_id;
|
|
ELSE
|
|
PERFORM delete_item(in_item_id);
|
|
END IF;
|
|
UPDATE items SET stack_size = dst_item_data.stack_size + in_count WHERE id = dst_item_data.id;
|
|
|
|
RETURN dst_item_data.id;
|
|
END $function$
|
|
|
|
|
|
-- merge_or_move_inventory_item(in_item_id bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint) -> bigint
|
|
-- oid: 58475 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.merge_or_move_inventory_item(in_item_id bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
remaining_stack_size BIGINT;
|
|
new_item_id BIGINT;
|
|
item_data items%ROWTYPE;
|
|
dst_item_data items%ROWTYPE;
|
|
BEGIN
|
|
SELECT INTO new_item_id merge_inventory_items(in_item_id, in_dst_inventory_id, in_dst_index, in_count);
|
|
|
|
IF new_item_id IS NULL THEN
|
|
SELECT INTO new_item_id move_inventory_item(in_item_id, in_dst_inventory_id, in_dst_index, in_count);
|
|
END IF;
|
|
|
|
RETURN new_item_id;
|
|
END $function$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- move_inventory_item(in_item_id bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint) -> bigint
|
|
-- oid: 58478 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.move_inventory_item(in_item_id bigint, in_dst_inventory_id bigint, in_dst_index bigint, in_count bigint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
remaining_stack_size BIGINT;
|
|
new_item_id BIGINT;
|
|
item_data items%ROWTYPE;
|
|
BEGIN
|
|
SELECT INTO STRICT item_data * FROM items WHERE id = in_item_id;
|
|
|
|
remaining_stack_size := item_data.stack_size - in_count;
|
|
|
|
IF remaining_stack_size < 0 THEN
|
|
RETURN NULL;
|
|
END IF;
|
|
|
|
-- log item tracking
|
|
PERFORM _add_item_trace_log('move_inventory_item', in_item_id, in_dst_inventory_id, NULL, in_dst_index);
|
|
|
|
IF remaining_stack_size > 0 THEN
|
|
item_data.stack_size := in_count;
|
|
item_data.position_index := in_dst_index;
|
|
item_data.inventory_id := in_dst_inventory_id;
|
|
SELECT INTO item_data.id nextval('items_id_seq');
|
|
INSERT INTO items VALUES(item_data.*) RETURNING id INTO new_item_id;
|
|
UPDATE items SET stack_size = remaining_stack_size WHERE id = in_item_id;
|
|
ELSE
|
|
UPDATE items SET inventory_id = in_dst_inventory_id, position_index = in_dst_index WHERE id = in_item_id;
|
|
new_item_id := in_item_id;
|
|
END IF;
|
|
|
|
RETURN new_item_id;
|
|
END $function$
|
|
|
|
|
|
-- overmap_delete_player_survival_data(in_player_id bigint) -> void
|
|
-- oid: 58479 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.overmap_delete_player_survival_data(in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM overmap_players WHERE player_id = in_player_id;
|
|
END $function$
|
|
|
|
|
|
-- overmap_load_player_survival_data(in_player_id bigint) -> TABLE(out_vehicle_id bigint, out_has_polar_psu boolean, out_overmap_location dune.vector)
|
|
-- oid: 58480 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.overmap_load_player_survival_data(in_player_id bigint)
|
|
RETURNS TABLE(out_vehicle_id bigint, out_has_polar_psu boolean, out_overmap_location dune.vector)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT vehicle_id, has_polar_psu, overmap_location FROM overmap_players WHERE player_id = in_player_id;
|
|
END $function$
|
|
|
|
|
|
-- overmap_save_player_survival_data(in_player_id bigint, in_vehicle_id bigint, in_has_polar_psu boolean, in_overmap_location dune.vector) -> void
|
|
-- oid: 58481 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.overmap_save_player_survival_data(in_player_id bigint, in_vehicle_id bigint, in_has_polar_psu boolean, in_overmap_location dune.vector)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
real_vehicle_id BigInt;
|
|
BEGIN
|
|
real_vehicle_id := (select id from actors where id=in_vehicle_id);
|
|
INSERT INTO
|
|
overmap_players(player_id, vehicle_id, has_polar_psu, overmap_location) VALUES(in_player_id, real_vehicle_id, in_has_polar_psu, in_overmap_location)
|
|
ON CONFLICT(player_id)
|
|
DO UPDATE SET
|
|
vehicle_id = real_vehicle_id, has_polar_psu = in_has_polar_psu, overmap_location = in_overmap_location
|
|
WHERE
|
|
overmap_players.player_id = in_player_id;
|
|
END $function$
|
|
|
|
|
|
-- ownership_handle_actor_delete(in_player_id bigint) -> void
|
|
-- oid: 58482 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.ownership_handle_actor_delete(in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
owned_totem_ids BIGINT[];
|
|
actors_with_permission BIGINT[];
|
|
BEGIN
|
|
|
|
-- Get owner entity ids (totems) where in_player_id is the owner
|
|
SELECT ARRAY_AGG(owner_entity_id) into owned_totem_ids
|
|
FROM permission_actor_rank
|
|
JOIN permission_actor ON actor_id = permission_actor_id
|
|
JOIN placeables on placeables.id = permission_actor_id
|
|
WHERE player_id = in_player_id AND rank = 1::smallint; -- 1:owner
|
|
|
|
-- Get actors where in_player_id is the owner
|
|
SELECT ARRAY_AGG(permission_actor_id) into actors_with_permission
|
|
FROM permission_actor_rank WHERE player_id = in_player_id AND rank = 1::smallint; -- 1:owner
|
|
|
|
-- Remove all permissions for those actors
|
|
IF cardinality(actors_with_permission) > 0 THEN
|
|
DELETE FROM permission_actor_rank WHERE permission_actor_id = ANY(actors_with_permission);
|
|
DELETE FROM MARKERS WHERE marker_hash_id = ANY(actors_with_permission);
|
|
|
|
PERFORM pg_notify('permission_notify_channel', format('owner_delete#{"PlayerId" : %s}', in_player_id));
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- parties_get_exclusive_operation_lock() -> void
|
|
-- oid: 58483 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.parties_get_exclusive_operation_lock()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM pg_advisory_xact_lock(9457135); -- Parties in leet :/
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- perform_notify_on_character_delete(in_user_id text) -> void
|
|
-- oid: 58484 kind: FUNCTION category: player_persistence
|
|
|
|
CREATE OR REPLACE FUNCTION dune.perform_notify_on_character_delete(in_user_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM pg_notify('player_info_notify_channel', format('character_deleted#%s', in_user_id));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- permission_actor_create_or_update_base_marker(in_actor_id bigint, in_player_id bigint, in_rank smallint) -> void
|
|
-- oid: 58485 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.permission_actor_create_or_update_base_marker(in_actor_id bigint, in_player_id bigint, in_rank smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_marker_type TEXT := 'HomeBase';
|
|
out_owner_id BIGINT;
|
|
out_owner_name Text;
|
|
out_dimension_index INTEGER;
|
|
out_x REAL;
|
|
out_y REAL;
|
|
out_z REAL;
|
|
out_totem_name Text;
|
|
out_map_name Text;
|
|
out_map_name_id SMALLINT;
|
|
out_actor_type smallint;
|
|
BEGIN
|
|
|
|
-- Get owner data
|
|
SELECT player_id, character_name
|
|
INTO out_owner_id, out_owner_name
|
|
FROM permission_actor_rank
|
|
JOIN player_state on player_controller_id = player_id
|
|
WHERE rank = 1::smallint AND permission_actor_id = in_actor_id
|
|
LIMIT 1;
|
|
|
|
-- Get target and totem data
|
|
SELECT dimension_index, (transform).location.x, (transform).location.y, (transform).location.z, actor_name, map, actor_type
|
|
INTO out_dimension_index, out_x, out_y, out_z, out_totem_name, out_map_name, out_actor_type
|
|
FROM permission_actor_rank
|
|
JOIN permission_actor on actor_id = permission_actor_id
|
|
JOIN player_state on player_controller_id = player_id
|
|
JOIN actors ON permission_actor_id = actors.id
|
|
WHERE permission_actor_id = in_actor_id AND player_id = in_player_id
|
|
LIMIT 1;
|
|
|
|
SELECT map_name_id
|
|
INTO out_map_name_id
|
|
FROM map_names
|
|
WHERE map_name = out_map_name;
|
|
|
|
IF out_actor_type = 3 OR out_actor_type = 4 THEN -- Totem || TotemSmall
|
|
INSERT INTO markers ("dimension_index", "marker_hash_id", "map_name_id", "marker", "area_id", "area_radius", "long_range", "payload")
|
|
VALUES(out_dimension_index,
|
|
in_actor_id,
|
|
out_map_name_id,
|
|
ROW(
|
|
out_marker_type,
|
|
out_x, out_y, out_z,
|
|
'EMarkerPayloadType::Permissions'
|
|
)::MARKER,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
jsonb_build_object(
|
|
'OwnerUID', out_owner_id,
|
|
'OwnerName', out_owner_name,
|
|
'TotemName', out_totem_name,
|
|
'TotemId', in_actor_id
|
|
)
|
|
)
|
|
ON CONFLICT (marker_hash_id, dimension_index, map_name_id)
|
|
DO UPDATE SET
|
|
marker = EXCLUDED.marker;
|
|
|
|
INSERT INTO player_markers ("dimension_index", "player_id", "marker_hash_id", "map_name_id", "discovery_level", "discovery_method", "payload")
|
|
VALUES(out_dimension_index,
|
|
in_player_id,
|
|
in_actor_id,
|
|
out_map_name_id,
|
|
3, -- EMarkerDiscoveryLevel::Discovered
|
|
10, -- EMarkerDiscoveryMethod::Permissions
|
|
'{}'::JSONB
|
|
)
|
|
ON CONFLICT (dimension_index, player_id, marker_hash_id, map_name_id)
|
|
DO NOTHING;
|
|
END IF;
|
|
|
|
END
|
|
$function$
|
|
|
|
|
|
-- permission_actor_destroy(in_actor_id bigint) -> void
|
|
-- oid: 58486 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.permission_actor_destroy(in_actor_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM permission_actor_rank WHERE permission_actor_id = in_actor_id;
|
|
DELETE FROM permission_actor WHERE actor_id = in_actor_id;
|
|
-- Destroy map markers related with this actor
|
|
DELETE FROM markers WHERE marker_hash_id = in_actor_id;
|
|
DELETE FROM player_markers WHERE marker_hash_id = in_actor_id;
|
|
|
|
PERFORM pg_notify('permission_notify_channel', format('destroy#{"ActorId" : %s}', in_actor_id));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- permission_actor_register(in_entry dune.actorpermissionentry, in_owner_rank dune.actorpermissionrankdata) -> void
|
|
-- oid: 58487 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.permission_actor_register(in_entry dune.actorpermissionentry, in_owner_rank dune.actorpermissionrankdata)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO
|
|
permission_actor("actor_id", "actor_name", "actor_type", "access_level", "is_child")
|
|
VALUES(in_entry.actor_id, in_entry.actor_name, in_entry.actor_type, in_entry.access_level, in_entry.is_child);
|
|
|
|
IF NOT in_entry.is_child THEN
|
|
INSERT INTO permission_actor_rank("permission_actor_id", "player_id", "rank")
|
|
VALUES(in_entry.actor_id, in_owner_rank.player_id, in_owner_rank.rank);
|
|
END IF;
|
|
|
|
-- there is no pg_notify here as the use cases where it may be needed are very low and we do not want to pay that cost. If we find any scenario where we need it, it can be added
|
|
END
|
|
$function$
|
|
|
|
|
|
-- permission_actor_takeover(in_entry dune.actorpermissionentry, in_owner_rank dune.actorpermissionrankdata) -> void
|
|
-- oid: 58488 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.permission_actor_takeover(in_entry dune.actorpermissionentry, in_owner_rank dune.actorpermissionrankdata)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_actor_id BIGINT;
|
|
found_guild_id BIGINT;
|
|
found_previous_owner BIGINT;
|
|
BEGIN
|
|
|
|
-- Check if the actor is already owned to avoid exploits
|
|
SELECT player_id into found_previous_owner FROM permission_actor_rank WHERE permission_actor_id = in_entry.actor_id AND rank = 1::smallint;
|
|
IF found_previous_owner IS NOT NULL THEN
|
|
RAISE NOTICE 'Player % trying to claim ownership over actor % already owned by player %.',
|
|
in_owner_rank.player_id, in_entry.actor_id, found_previous_owner;
|
|
return;
|
|
END IF;
|
|
|
|
SELECT actor_id FROM permission_actor WHERE actor_id = in_entry.actor_id INTO found_actor_id;
|
|
IF NOT FOUND THEN
|
|
PERFORM permission_actor_register(in_entry, in_owner_rank);
|
|
RETURN;
|
|
END IF;
|
|
|
|
SELECT guild_id FROM guild_members WHERE player_id = in_entry.actor_id INTO found_guild_id;
|
|
IF NOT FOUND THEN
|
|
found_guild_id := 0;
|
|
END IF;
|
|
|
|
DELETE FROM permission_actor_rank WHERE permission_actor_id = in_entry.actor_id;
|
|
INSERT INTO permission_actor_rank("permission_actor_id", "player_id", "rank")
|
|
VALUES(in_entry.actor_id, in_owner_rank.player_id, in_owner_rank.rank);
|
|
|
|
PERFORM pg_notify('permission_notify_channel', format('takeover#{"ActorId" : %s , "PlayerId" : %s, "PlayerGuildId" : %s}', in_entry.actor_id, in_owner_rank.player_id, found_guild_id));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- permission_actor_update_marker_location(in_actor_id bigint, in_location_x real, in_location_y real, in_location_z real) -> void
|
|
-- oid: 58489 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.permission_actor_update_marker_location(in_actor_id bigint, in_location_x real, in_location_y real, in_location_z real)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE markers SET marker =
|
|
(
|
|
(marker).marker_type,
|
|
in_location_x,
|
|
in_location_y,
|
|
in_location_z,
|
|
(marker).payload_type
|
|
)
|
|
WHERE marker_hash_id = in_actor_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- permission_remove_player_rank(in_actor_id bigint, in_player_id bigint) -> void
|
|
-- oid: 58490 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.permission_remove_player_rank(in_actor_id bigint, in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM permission_actor_rank WHERE permission_actor_id = in_actor_id AND player_id = in_player_id;
|
|
|
|
-- Remove from player_markers using player id and, actor id as hash id
|
|
DELETE FROM player_markers WHERE player_id = in_player_id AND marker_hash_id = in_actor_id;
|
|
|
|
PERFORM pg_notify('permission_notify_channel', format('remove_rank#{"ActorId" : %s , "PlayerId" : %s}', in_actor_id, in_player_id));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- permission_set_access_level(in_actor_id bigint, in_access_level smallint) -> void
|
|
-- oid: 58491 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.permission_set_access_level(in_actor_id bigint, in_access_level smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE permission_actor SET access_level = in_access_level WHERE permission_actor.actor_id = in_actor_id;
|
|
|
|
PERFORM pg_notify('permission_notify_channel', format('set_access_level#{"ActorId" : %s , "AccessLevel" : %s}', in_actor_id, in_access_level));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- permission_set_name(in_actor_id bigint, in_name text) -> void
|
|
-- oid: 58492 kind: FUNCTION category: permission
|
|
|
|
CREATE OR REPLACE FUNCTION dune.permission_set_name(in_actor_id bigint, in_name text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE permission_actor SET actor_name = in_name WHERE permission_actor.actor_id = in_actor_id;
|
|
|
|
UPDATE markers SET marker =
|
|
(
|
|
(marker).marker_type,
|
|
(marker).x,
|
|
(marker).y,
|
|
(marker).z,
|
|
(marker).payload_type
|
|
),
|
|
payload = jsonb_set(payload, '{TotemName}', to_jsonb(in_name) , false)
|
|
WHERE marker_hash_id = in_actor_id;
|
|
|
|
PERFORM pg_notify('permission_notify_channel', format('set_name#{"ActorId" : %s , "Name" : "%s"}', in_actor_id, in_name));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- permission_set_player_rank(in_actor_id bigint, in_player_id bigint, in_rank smallint, in_map_id text) -> void
|
|
-- oid: 58493 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.permission_set_player_rank(in_actor_id bigint, in_player_id bigint, in_rank smallint, in_map_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_actor_id BIGINT;
|
|
found_guild_id BIGINT;
|
|
BEGIN
|
|
SELECT permission_actor_id FROM permission_actor_rank WHERE permission_actor_id = in_actor_id AND player_id = in_player_id INTO found_actor_id;
|
|
IF NOT FOUND THEN
|
|
INSERT INTO permission_actor_rank("permission_actor_id", "player_id", "rank") VALUES(in_actor_id, in_player_id, in_rank);
|
|
ELSE
|
|
UPDATE permission_actor_rank SET rank = in_rank WHERE permission_actor_rank.permission_actor_id = in_actor_id AND player_id = in_player_id;
|
|
END IF;
|
|
|
|
SELECT guild_id FROM guild_members WHERE player_id = in_actor_id INTO found_guild_id;
|
|
IF NOT FOUND THEN
|
|
found_guild_id := 0;
|
|
END IF;
|
|
|
|
PERFORM permission_actor_create_or_update_base_marker(in_actor_id, in_player_id, in_rank);
|
|
|
|
PERFORM pg_notify('permission_notify_channel', format('set_rank#{"ActorId" : %s , "PlayerId" : %s, "PlayerGuildId" : %s, "Rank" : %s, "Map" : %s}', in_actor_id, in_player_id, found_guild_id, in_rank, in_map_id));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- player_purchased_item_from_vendor(in_vendor_id text, in_player_id bigint, in_template_id text, in_amount_bought integer) -> void
|
|
-- oid: 58494 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.player_purchased_item_from_vendor(in_vendor_id text, in_player_id bigint, in_template_id text, in_amount_bought integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
-- Add/update stock
|
|
IF NOT EXISTS
|
|
( SELECT * FROM vendor_stock_state
|
|
WHERE vendor_id = in_vendor_id and player_id = in_player_id AND template_id = in_template_id)
|
|
THEN
|
|
INSERT INTO vendor_stock_state(vendor_id, player_id, template_id, amount_bought) VALUES(in_vendor_id, in_player_id, in_template_id, in_amount_bought);
|
|
ELSE
|
|
UPDATE vendor_stock_state SET amount_bought = amount_bought + in_amount_bought
|
|
WHERE vendor_id = in_vendor_id and player_id = in_player_id AND template_id = in_template_id;
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- player_state_update(in_data dune.playerstateupdatedata[]) -> void
|
|
-- oid: 58495 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.player_state_update(in_data dune.playerstateupdatedata[])
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
-- online -> offline
|
|
with
|
|
update_data as (select * from unnest(in_data))
|
|
update encrypted_player_state as ps
|
|
set online_status = update_data.online_status
|
|
from update_data
|
|
where ps.player_controller_id = update_data.player_controller_id
|
|
and ps.server_id = update_data.current_server_id -- make sure we don't update if the player is already online somewhere else
|
|
and update_data.online_status != 'Online'
|
|
and ps.online_status != update_data.online_status; -- avoid unnecessary data changes
|
|
|
|
-- offline -> online
|
|
with
|
|
update_data as (select * from unnest(in_data))
|
|
update encrypted_player_state as ps
|
|
set online_status = update_data.online_status,
|
|
server_id = update_data.current_server_id
|
|
from update_data
|
|
where ps.player_controller_id = update_data.player_controller_id
|
|
and update_data.online_status = 'Online'
|
|
and (ps.server_id is null or ps.server_id != update_data.current_server_id or ps.online_status != update_data.online_status); -- avoid unnecessary data changes
|
|
|
|
with
|
|
update_data as (select * from unnest(in_data))
|
|
update encrypted_player_state as ps
|
|
set reconnect_grace_period_end = update_data.reconnect_grace_period_end
|
|
from update_data
|
|
where ps.player_controller_id = update_data.player_controller_id
|
|
and not update_data.reconnect_grace_period_end is null;
|
|
|
|
with
|
|
update_data as (select * from unnest(in_data))
|
|
update encrypted_player_state as ps
|
|
set
|
|
last_avatar_activity = (update_data.on_disconnect).last_online_time AT TIME ZONE 'UTC',
|
|
previous_server_partition_id = (update_data.on_disconnect).previous_server_partition_id
|
|
from update_data
|
|
where ps.player_controller_id = update_data.player_controller_id
|
|
and not update_data.on_disconnect is null;
|
|
$function$
|
|
|
|
|
|
-- pledge_guild_allegiance(in_guild_id bigint, in_guild_leader_player_id bigint, in_neutral_faction_id smallint) -> void
|
|
-- oid: 58496 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.pledge_guild_allegiance(in_guild_id bigint, in_guild_leader_player_id bigint, in_neutral_faction_id smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
guilds_changed SMALLINT := 0;
|
|
guild_data_record record;
|
|
guild_leader_record record;
|
|
guild_leader_faction_id SMALLINT;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
SELECT * INTO guild_leader_record FROM guild_members
|
|
LEFT JOIN player_faction ON actor_id = in_guild_leader_player_id
|
|
WHERE player_id = in_guild_leader_player_id AND is_player_guild_admin(in_guild_leader_player_id, in_guild_id);
|
|
|
|
IF guild_leader_record IS NULL THEN
|
|
RAISE EXCEPTION 'Trying to change a faction for a player: % without a guild', in_guild_leader_player_id;
|
|
END IF;
|
|
|
|
SELECT * INTO guild_data_record FROM guilds WHERE guild_id = in_guild_id;
|
|
IF guild_data_record IS NULL THEN
|
|
RAISE EXCEPTION 'Trying to change a faction in non existing guild: %', in_guild_id;
|
|
END IF;
|
|
|
|
IF guild_leader_record.faction_id IS NULL THEN
|
|
guild_leader_faction_id := in_neutral_faction_id;
|
|
ELSE
|
|
guild_leader_faction_id := guild_leader_record.faction_id;
|
|
END IF;
|
|
|
|
if guild_leader_faction_id = in_neutral_faction_id THEN
|
|
RAISE EXCEPTION 'Guild leader has neutral faction, cannot change faction to neutral';
|
|
ELSEIF guild_data_record.guild_faction = guild_leader_faction_id THEN
|
|
RAISE EXCEPTION 'Guild already has the same allegiance: % as the guild leader %', in_guild_id, guild_data_record.guild_faction;
|
|
END IF;
|
|
|
|
UPDATE guilds SET guild_faction = guild_leader_faction_id WHERE guilds.guild_id = in_guild_id;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('pledge_guild_allegiance#{"GuildId" : %s , "OldGuildFactionDbId" : %s, "NewGuildFactionDbId" : %s}', in_guild_id, guild_data_record.guild_faction, guild_leader_faction_id));
|
|
PERFORM remove_guild_members(ARRAY(
|
|
SELECT player_id FROM guild_members
|
|
JOIN player_faction ON guild_members.player_id = player_faction.actor_id
|
|
WHERE guild_leader_faction_id != player_faction.faction_id AND player_faction.faction_id != in_neutral_faction_id AND guild_members.guild_id = in_guild_id),
|
|
in_guild_id,
|
|
2::smallint
|
|
);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- produce_spicefield_manifest(in_map_name text, in_dimension_index integer) -> TABLE(server text, type_id integer, inactive_fields integer, requested_fields integer)
|
|
-- oid: 58497 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.produce_spicefield_manifest(in_map_name text, in_dimension_index integer)
|
|
RETURNS TABLE(server text, type_id integer, inactive_fields integer, requested_fields integer)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
return query
|
|
select sa.server_id, sa.spicefield_type_id, sa.inactive_fields_of_type, sa.requested_spawned_of_type
|
|
from spicefield_server_availability sa join spicefield_types st
|
|
on sa.spicefield_type_id = st.spicefield_type_id
|
|
where st.map_name = in_map_name and st.dimension_index = in_dimension_index
|
|
order by server_id;
|
|
end $function$
|
|
|
|
|
|
-- promote_guild_member(in_guild_id bigint, in_player_id bigint, in_new_role smallint) -> void
|
|
-- oid: 58498 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.promote_guild_member(in_guild_id bigint, in_player_id bigint, in_new_role smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- check if new admin is actualy in guild
|
|
IF NOT EXISTS(SELECT FROM guild_members WHERE player_id = in_player_id AND guild_id = in_guild_id) THEN
|
|
RAISE EXCEPTION 'Trying to promte player not in guild %.', in_player_id;
|
|
END IF;
|
|
|
|
if in_new_role = 100 THEN
|
|
-- set admin to member
|
|
UPDATE guild_members SET role_id = 50 WHERE guild_id = in_guild_id AND role_id = 100;
|
|
END IF;
|
|
|
|
-- set new player to new role
|
|
UPDATE guild_members SET role_id = in_new_role WHERE player_id = in_player_id AND guild_id = in_guild_id;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('promote_player#{"PlayerId" : %s , "GuildId" : %s, "NewRole" : %s}', in_player_id, in_guild_id, in_new_role));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- promote_new_party_leader(in_party_id bigint) -> void
|
|
-- oid: 58499 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.promote_new_party_leader(in_party_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_current_leader BIGINT;
|
|
out_new_leader BIGINT;
|
|
BEGIN
|
|
PERFORM parties_get_exclusive_operation_lock();
|
|
|
|
-- get current leader
|
|
SELECT party_leader_id FROM parties where party_id = in_party_id into out_current_leader;
|
|
IF out_current_leader IS NULL THEN
|
|
RAISE EXCEPTION 'Promoting a player to a non existing party %.', in_party_id;
|
|
END IF;
|
|
|
|
-- get first member in the party that is online and is not the party leader
|
|
SELECT party_members.player_id INTO out_new_leader FROM party_members
|
|
JOIN player_state ON player_state.player_controller_id = party_members.player_id
|
|
WHERE party_members.party_id = in_party_id
|
|
AND party_members.player_id <> out_current_leader
|
|
AND player_state.online_status = 'Online';
|
|
|
|
IF out_new_leader IS NOT NULL THEN
|
|
-- promote
|
|
UPDATE parties SET party_leader_id = out_new_leader WHERE party_id = in_party_id;
|
|
PERFORM pg_notify('party_notify_channel', format('promote_party_leader#{"PartyId" : %s, "PlayerId" : %s}', in_party_id, out_new_leader));
|
|
END IF;
|
|
|
|
END
|
|
$function$
|
|
|
|
|
|
-- promote_party_leader_to(in_party_id bigint, in_player_id bigint) -> void
|
|
-- oid: 58500 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.promote_party_leader_to(in_party_id bigint, in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_current_leader BIGINT;
|
|
out_new_leader BIGINT;
|
|
BEGIN
|
|
PERFORM parties_get_exclusive_operation_lock();
|
|
|
|
-- get current leader
|
|
SELECT party_leader_id FROM parties where party_id = in_party_id into out_current_leader;
|
|
IF out_current_leader IS NULL THEN
|
|
RAISE EXCEPTION 'Promoting a player to a non existing party %.', in_party_id;
|
|
END IF;
|
|
|
|
-- get new member if it is online
|
|
SELECT party_members.player_id INTO out_new_leader FROM party_members
|
|
JOIN player_state ON player_state.player_controller_id = party_members.player_id
|
|
WHERE party_members.party_id = in_party_id
|
|
AND party_members.player_id = in_player_id
|
|
AND player_state.online_status = 'Online';
|
|
|
|
IF out_new_leader IS NOT NULL THEN
|
|
-- promote
|
|
UPDATE parties SET party_leader_id = out_new_leader WHERE party_id = in_party_id;
|
|
PERFORM pg_notify('party_notify_channel', format('promote_party_leader#{"PartyId" : %s, "PlayerId" : %s}', in_party_id, out_new_leader));
|
|
ELSE
|
|
RAISE EXCEPTION 'Promopromoting player %, which is offline or does not belong to the party.', in_party_id;
|
|
-- pg_notify for feedback?
|
|
END IF;
|
|
|
|
END
|
|
$function$
|
|
|
|
|
|
-- purchase_specialization_keystone(in_player_id bigint, in_keystone text) -> boolean
|
|
-- oid: 58501 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.purchase_specialization_keystone(in_player_id bigint, in_keystone text)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_id SMALLINT;
|
|
inserted_id SMALLINT;
|
|
BEGIN
|
|
SELECT id FROM specialization_keystones_map INTO found_id WHERE name = in_keystone;
|
|
IF found_id IS NULL THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
INSERT INTO purchased_specialization_keystones (player_id, keystone_id) VALUES (in_player_id, found_id)
|
|
ON CONFLICT DO NOTHING
|
|
RETURNING keystone_id INTO inserted_id;
|
|
|
|
IF inserted_id IS NULL THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
RETURN TRUE;
|
|
END $function$
|
|
|
|
|
|
-- record_deactivated_spice_field(in_server_id text, in_spicefield_type_id integer) -> void
|
|
-- oid: 58502 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.record_deactivated_spice_field(in_server_id text, in_spicefield_type_id integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE spicefield_server_availability
|
|
SET inactive_fields_of_type = inactive_fields_of_type + 1
|
|
WHERE server_id = in_server_id AND spicefield_type_id = in_spicefield_type_id;
|
|
|
|
UPDATE spicefield_types
|
|
SET current_globally_active = current_globally_active - 1
|
|
WHERE spicefield_type_id = in_spicefield_type_id;
|
|
END; $function$
|
|
|
|
|
|
-- record_dungeon_completion(in_dungeon_id text, in_difficulty integer, in_duration_ms integer, players_ids bigint[]) -> void
|
|
-- oid: 58503 kind: FUNCTION category: dungeon
|
|
|
|
CREATE OR REPLACE FUNCTION dune.record_dungeon_completion(in_dungeon_id text, in_difficulty integer, in_duration_ms integer, players_ids bigint[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
new_completion_id BIGINT;
|
|
begin
|
|
INSERT INTO dungeon_completion VALUES (DEFAULT, in_dungeon_id, in_difficulty, in_duration_ms, array_length(players_ids, 1))
|
|
RETURNING completion_id INTO new_completion_id;
|
|
INSERT INTO dungeon_completion_players SELECT t.player_id, new_completion_id FROM UNNEST(players_ids) AS t(player_id);
|
|
end
|
|
$function$
|
|
|
|
|
|
-- record_logoff_persistence_end_time(in_player_pawn_id bigint, in_logoff_persistence_end_time timestamp without time zone) -> void
|
|
-- oid: 58504 kind: FUNCTION category: player_persistence
|
|
|
|
CREATE OR REPLACE FUNCTION dune.record_logoff_persistence_end_time(in_player_pawn_id bigint, in_logoff_persistence_end_time timestamp without time zone)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE encrypted_player_state
|
|
SET logoff_persistence_end_time = in_logoff_persistence_end_time
|
|
WHERE player_pawn_id = in_player_pawn_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- record_static_shifting_sand(in_id text, in_alpha double precision, in_x double precision, in_y double precision, in_last_modified_time bigint) -> void
|
|
-- oid: 58505 kind: FUNCTION category: shifting_sand
|
|
|
|
CREATE OR REPLACE FUNCTION dune.record_static_shifting_sand(in_id text, in_alpha double precision, in_x double precision, in_y double precision, in_last_modified_time bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO shiftingsands_data(id, alpha, x, y, last_modified_time) Values(in_id, in_alpha, in_x, in_y, to_timestamp(in_last_modified_time))
|
|
ON CONFLICT(id) DO UPDATE SET alpha = $2, last_modified_time = to_timestamp(in_last_modified_time);
|
|
END $function$
|
|
|
|
|
|
-- record_unreadied_spice_fields(in_server_id text, in_spicefield_type_id integer, in_num_unreadied integer) -> void
|
|
-- oid: 58506 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.record_unreadied_spice_fields(in_server_id text, in_spicefield_type_id integer, in_num_unreadied integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE spicefield_types
|
|
SET current_globally_primed = current_globally_primed - in_num_unreadied
|
|
WHERE spicefield_type_id = in_spicefield_type_id;
|
|
|
|
UPDATE spicefield_server_availability
|
|
SET inactive_fields_of_type = inactive_fields_of_type + in_num_unreadied
|
|
WHERE server_id = in_server_id AND spicefield_type_id = in_spicefield_type_id;
|
|
END; $function$
|
|
|
|
|
|
-- register_lore_pickup(in_lore_pickup_ids text[]) -> SETOF smallint
|
|
-- oid: 58507 kind: FUNCTION category: server
|
|
|
|
CREATE OR REPLACE FUNCTION dune.register_lore_pickup(in_lore_pickup_ids text[])
|
|
RETURNS SETOF smallint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN query WITH
|
|
input AS (
|
|
SELECT UNNEST (in_lore_pickup_ids) as lore_pickup_id
|
|
),
|
|
existing AS (
|
|
SELECT incremental_id, lore_pickup_id FROM lore_pickups WHERE lore_pickup_id = ANY(SELECT lore_pickup_id FROM input)
|
|
),
|
|
inserted AS (
|
|
INSERT INTO lore_pickups("lore_pickup_id") SELECT lore_pickup_id FROM input WHERE NOT lore_pickup_id = ANY(SELECT lore_pickup_id FROM existing) returning incremental_id, lore_pickup_id
|
|
),
|
|
combined AS (
|
|
SELECT incremental_id, lore_pickup_id FROM existing UNION ALL SELECT incremental_id, lore_pickup_id FROM inserted
|
|
)
|
|
SELECT incremental_id FROM combined ORDER BY lore_pickup_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- register_new_factions(factions text[]) -> TABLE(faction_id smallint, faction_name text)
|
|
-- oid: 58508 kind: FUNCTION category: faction
|
|
|
|
CREATE OR REPLACE FUNCTION dune.register_new_factions(factions text[])
|
|
RETURNS TABLE(faction_id smallint, faction_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_role_id SMALLINT;
|
|
BEGIN
|
|
-- Lock the factions table to prevent concurrent modifications. This is only done once on server start up.
|
|
LOCK TABLE factions IN SHARE ROW EXCLUSIVE MODE;
|
|
WITH new_factions AS (
|
|
SELECT f FROM UNNEST(factions) f LEFT JOIN factions ON f = factions.name WHERE id IS NULL
|
|
)
|
|
INSERT INTO factions (name) SELECT * FROM new_factions ON CONFLICT DO NOTHING;
|
|
RETURN QUERY SELECT * from factions;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- register_new_tutorials(tutorials text[]) -> TABLE(tutorial_id smallint, tutorial_name text)
|
|
-- oid: 58509 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.register_new_tutorials(tutorials text[])
|
|
RETURNS TABLE(tutorial_id smallint, tutorial_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
-- Lock the tutorials table to prevent concurrent modifications. This is only done once on server start up.
|
|
LOCK TABLE tutorials IN SHARE ROW EXCLUSIVE MODE;
|
|
|
|
WITH new_tutorials AS (
|
|
SELECT q FROM unnest(tutorials) q LEFT JOIN tutorials ON q = tutorials.name WHERE id is NULL
|
|
)
|
|
INSERT INTO tutorials (name) SELECT * FROM new_tutorials;
|
|
|
|
RETURN QUERY SELECT * from tutorials;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- register_per_player_lore_pickup(in_lore_pickup_ids text[], in_use_temporary boolean) -> SETOF smallint
|
|
-- oid: 58510 kind: FUNCTION category: server
|
|
|
|
CREATE OR REPLACE FUNCTION dune.register_per_player_lore_pickup(in_lore_pickup_ids text[], in_use_temporary boolean)
|
|
RETURNS SETOF smallint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF in_use_temporary THEN
|
|
RETURN query select * from register_temporary_lore_pickup(in_lore_pickup_ids);
|
|
ELSE
|
|
RETURN query select * from register_lore_pickup(in_lore_pickup_ids);
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- register_spawned_actor(in_spawner_id bigint, in_actor_id bigint) -> void
|
|
-- oid: 58511 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.register_spawned_actor(in_spawner_id bigint, in_actor_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO actor_spawner_actors(spawner_id, actor_id) VALUES(in_spawner_id, in_actor_id);
|
|
END $function$
|
|
|
|
|
|
-- register_spice_field_server_resources(in_server_id text, in_spicefield_type_ids integer[], in_inactive_fields_of_types integer[]) -> void
|
|
-- oid: 58512 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.register_spice_field_server_resources(in_server_id text, in_spicefield_type_ids integer[], in_inactive_fields_of_types integer[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO spicefield_server_availability(server_id, spicefield_type_id, inactive_fields_of_type)
|
|
SELECT in_server_id, unnest(in_spicefield_type_ids), unnest(in_inactive_fields_of_types)
|
|
ON CONFLICT(server_id, spicefield_type_id)
|
|
DO UPDATE SET server_id = excluded.server_id, spicefield_type_id = excluded.spicefield_type_id, inactive_fields_of_type = excluded.inactive_fields_of_type;
|
|
END; $function$
|
|
|
|
|
|
-- register_temporary_lore_pickup(in_lore_pickup_ids text[]) -> SETOF smallint
|
|
-- oid: 58513 kind: FUNCTION category: server
|
|
|
|
CREATE OR REPLACE FUNCTION dune.register_temporary_lore_pickup(in_lore_pickup_ids text[])
|
|
RETURNS SETOF smallint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN query WITH
|
|
input AS (
|
|
SELECT UNNEST (in_lore_pickup_ids) as lore_pickup_id
|
|
),
|
|
existing AS (
|
|
SELECT incremental_id, lore_pickup_id FROM lore_pickups_temporary WHERE lore_pickup_id = ANY(SELECT lore_pickup_id FROM input)
|
|
),
|
|
inserted AS (
|
|
INSERT INTO lore_pickups_temporary("lore_pickup_id") SELECT lore_pickup_id FROM input WHERE NOT lore_pickup_id = ANY(SELECT lore_pickup_id FROM existing) returning incremental_id, lore_pickup_id
|
|
),
|
|
combined AS (
|
|
SELECT incremental_id, lore_pickup_id FROM existing UNION ALL SELECT incremental_id, lore_pickup_id FROM inserted
|
|
)
|
|
SELECT incremental_id FROM combined ORDER BY lore_pickup_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- reject_guild_invite(in_invite_id bigint) -> void
|
|
-- oid: 58514 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.reject_guild_invite(in_invite_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
player_id BIGINT := 0;
|
|
guild_id BIGINT := 0;
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- check if invite exists
|
|
SELECT guild_invites.player_id, guild_invites.guild_id FROM guild_invites WHERE invite_id = in_invite_id INTO player_id, guild_id;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trying to remove non exiting invite %.', in_invite_id;
|
|
END IF;
|
|
|
|
DELETE FROM guild_invites WHERE invite_id = in_invite_id;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('reject_invite#{"PlayerId" : %s , "GuildId" : %s}', player_id, guild_id));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- remove_aborted_authority_transfer_actors(in_partition_id bigint) -> SETOF dune.actorspawninfo
|
|
-- oid: 58515 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_aborted_authority_transfer_actors(in_partition_id bigint)
|
|
RETURNS SETOF dune.actorspawninfo
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
WITH removed_actors AS (
|
|
DELETE FROM actor_state WHERE actor_state.state = 'AbortedAuthorityTransfer'
|
|
RETURNING actor_state.actor_id
|
|
)
|
|
SELECT a.id, a.class AS class_name, a.transform, a.partition_id, a.dimension_index
|
|
FROM actors AS a
|
|
INNER JOIN removed_actors ON a.id = removed_actors.actor_id
|
|
WHERE a.partition_id = in_partition_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- 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$
|
|
|
|
|
|
-- remove_communinet_player_channel(in_account_id bigint, in_channel_name text) -> void
|
|
-- oid: 58517 kind: FUNCTION category: communinet
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_communinet_player_channel(in_account_id bigint, in_channel_name text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM communinet_player_channels WHERE account_id = in_account_id AND channel_name = in_channel_name;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- remove_guild_members(in_player_ids bigint[], in_guild_id bigint, in_remove_reason smallint) -> void
|
|
-- oid: 58518 kind: FUNCTION category: guild
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_guild_members(in_player_ids bigint[], in_guild_id bigint, in_remove_reason smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_guild_name TEXT;
|
|
players_removed BIGINT[];
|
|
BEGIN
|
|
PERFORM guilds_get_exclusive_operation_lock();
|
|
|
|
-- check if guild exists
|
|
SELECT guild_name INTO out_guild_name FROM guilds WHERE guild_id = in_guild_id;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trying to disband non existing guild %.', in_guild_id;
|
|
END IF;
|
|
|
|
WITH removed_members AS (
|
|
DELETE FROM guild_members
|
|
WHERE player_id = ANY(in_player_ids) AND NOT is_player_guild_admin(player_id, in_guild_id)
|
|
RETURNING *
|
|
) SELECT array_agg(player_id) from removed_members INTO players_removed;
|
|
|
|
PERFORM pg_notify('guild_notify_channel', format('remove_players#{"PlayerIds" : [%s] , "GuildId" : %s, "GuildName" : "%s", "GuildRemoveReason" : %s}', ARRAY_TO_STRING(players_removed, ','), in_guild_id, out_guild_name, in_remove_reason));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- remove_items(items_to_remove text[]) -> void
|
|
-- oid: 58519 kind: FUNCTION category: items_purge
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_items(items_to_remove text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
PERFORM delete_items(
|
|
(
|
|
SELECT array_agg(id)
|
|
FROM items
|
|
WHERE template_id = ANY (items_to_remove)
|
|
)
|
|
);
|
|
end;
|
|
$function$
|
|
|
|
|
|
-- remove_items_and_recipes(items_to_remove text[], recipes_to_remove text[]) -> void
|
|
-- oid: 58520 kind: FUNCTION category: items_purge
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_items_and_recipes(items_to_remove text[], recipes_to_remove text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
declare
|
|
items_to_remove_filtered text[];
|
|
recipes_to_remove_filtered text[];
|
|
begin
|
|
lock table removed_items, removed_recipes, actors, fgl_entities, items in exclusive mode;
|
|
|
|
-- get the items in items_to_remove that are not in removed_items
|
|
items_to_remove_filtered := get_items_to_remove(items_to_remove);
|
|
|
|
-- remove items from fgl entities
|
|
perform remove_items_or_recipes_from_fgl_entities(items_to_remove_filtered);
|
|
|
|
-- get the recipes in recipes_to_remove that are not in removed_recipes
|
|
recipes_to_remove_filtered := get_recipes_to_remove(recipes_to_remove);
|
|
|
|
-- removes the requests that contain items or recipes from fgl_entities.
|
|
perform remove_items_or_recipes_from_fgl_entities(recipes_to_remove_filtered);
|
|
|
|
-- delete the items
|
|
perform remove_items(items_to_remove_filtered);
|
|
|
|
-- remove the recipes from actors known item recipes
|
|
perform remove_recipes_from_actor_properties(recipes_to_remove_filtered);
|
|
|
|
-- insert removed items and recipes in their respective tables
|
|
perform update_removed_items_and_recipes(items_to_remove_filtered, recipes_to_remove_filtered);
|
|
end
|
|
$function$
|
|
|
|
|
|
-- remove_items_or_recipes_from_fgl_entities(item_or_recipes text[]) -> void
|
|
-- oid: 58521 kind: FUNCTION category: items_purge
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_items_or_recipes_from_fgl_entities(item_or_recipes text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
declare
|
|
item_or_recipe text;
|
|
ent_id bigint;
|
|
components_data jsonb;
|
|
components_data_updated jsonb;
|
|
request jsonb;
|
|
item_or_recipe_found boolean;
|
|
updated_requests jsonb;
|
|
ingredient_allocation jsonb;
|
|
item_alloc_node jsonb;
|
|
allocated_item jsonb;
|
|
allocated_ingredient_info record;
|
|
begin
|
|
drop table if exists allocated_ingredients_info_temp;
|
|
create temp table allocated_ingredients_info_temp (item_unique_id bigint, amount bigint);
|
|
if array_length(item_or_recipes, 1) is null then
|
|
return;
|
|
end if;
|
|
foreach item_or_recipe in array(item_or_recipes)
|
|
loop
|
|
for ent_id, components_data in select entity_id, components
|
|
from fgl_entities
|
|
where components->'FItemCraftingComponent' is not null
|
|
loop
|
|
components_data_updated := components_data;
|
|
if jsonb_array_length(components_data_updated->'FItemCraftingComponent'->1->'RequestsQueue') < 1 then
|
|
return;
|
|
end if;
|
|
loop
|
|
item_or_recipe_found := false;
|
|
for request in select value::jsonb
|
|
from jsonb_array_elements(components_data_updated->'FItemCraftingComponent'->1->'RequestsQueue')
|
|
loop
|
|
if (request->'RecipeId'->>'Name' = item_or_recipe or
|
|
exists (select 1 from jsonb_array_elements(request->'ResultItems') where value->'ItemTemplateId'->>'Name' = item_or_recipe) or
|
|
exists (select 1 from jsonb_array_elements(request->'IngredientAllocations') where value->'ItemAllocNodes'->0->'ItemTemplateId'->>'Name' = item_or_recipe)) then
|
|
insert into allocated_ingredients_info_temp (item_unique_id, amount)
|
|
select (item->>'ItemUniqueId')::BigInt, (item->>'ItemAmount')::BigInt from (
|
|
select jsonb_array_elements(node->'AllocatedItems') as item, node as outer_node from (
|
|
select jsonb_array_elements(allocation->'ItemAllocNodes') as node from (
|
|
select jsonb_array_elements(request->'IngredientAllocations') as allocation
|
|
) allocations
|
|
) nodes
|
|
) items;
|
|
updated_requests := (select jsonb_agg(value) from jsonb_array_elements(components_data_updated->'FItemCraftingComponent'->1->'RequestsQueue') where value::jsonb != request);
|
|
if updated_requests is null then
|
|
components_data_updated := jsonb_set(components_data_updated, '{FItemCraftingComponent,1,RequestsQueue}', '[]'::jsonb);
|
|
components_data_updated := jsonb_set(components_data_updated, '{FItemCraftingComponent,1,State}', '"Idle"'::jsonb);
|
|
components_data_updated := jsonb_set(components_data_updated, '{FItemCraftingComponent,1,TotalTimeToCraftInSec}', '0'::jsonb);
|
|
components_data_updated := jsonb_set(components_data_updated, '{FItemCraftingComponent,1,PreviouslyCompletedTimeToCraftInSec}', '0'::jsonb);
|
|
else
|
|
components_data_updated := jsonb_set(components_data_updated, '{FItemCraftingComponent,1,RequestsQueue}', updated_requests);
|
|
end if;
|
|
item_or_recipe_found := true;
|
|
exit;
|
|
end if;
|
|
end loop;
|
|
exit when not item_or_recipe_found;
|
|
end loop;
|
|
update fgl_entities
|
|
set components = components_data_updated
|
|
where entity_id = ent_id;
|
|
end loop;
|
|
end loop;
|
|
|
|
for allocated_ingredient_info in select * from allocated_ingredients_info_temp
|
|
loop
|
|
perform delete_inventory_item(allocated_ingredient_info.item_unique_id, allocated_ingredient_info.amount);
|
|
end loop;
|
|
|
|
drop table allocated_ingredients_info_temp;
|
|
end;
|
|
$function$
|
|
|
|
|
|
-- remove_members_offline_for(in_interval_seconds integer) -> void
|
|
-- oid: 58522 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_members_offline_for(in_interval_seconds integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM parties_get_exclusive_operation_lock();
|
|
|
|
PERFORM remove_party_member(party_members.player_id, 0::SMALLINT) FROM party_members
|
|
JOIN player_state ON player_state.player_controller_id = party_members.player_id
|
|
WHERE player_state.online_status = 'Offline'
|
|
AND CURRENT_TIMESTAMP > player_state.last_avatar_activity + INTERVAL '1 second' * in_interval_seconds;
|
|
|
|
END
|
|
$function$
|
|
|
|
|
|
-- remove_party_invite(in_invite_id bigint, in_remove_reason smallint) -> void
|
|
-- oid: 58523 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_party_invite(in_invite_id bigint, in_remove_reason smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_sender_player_id BIGINT;
|
|
out_player_id BIGINT;
|
|
BEGIN
|
|
-- delete invite
|
|
IF in_invite_id IS NOT NULL THEN
|
|
DELETE FROM party_invites WHERE invite_id = in_invite_id RETURNING player_id, sender_player_id INTO out_player_id, out_sender_player_id;
|
|
PERFORM pg_notify('party_notify_channel', format('remove_invite#{"InviteId" : %s, "Reason" : %s, "SenderId" : %s, "PlayerId" : %s}', in_invite_id, in_remove_reason, out_sender_player_id, out_player_id));
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- remove_party_member(in_player_id bigint, in_remove_reason smallint) -> void
|
|
-- oid: 58524 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_party_member(in_player_id bigint, in_remove_reason smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
out_party_id BIGINT;
|
|
out_player_platform_name TEXT;
|
|
member_count BIGINT;
|
|
out_platform_members_count BIGINT;
|
|
removed_player_id BIGINT;
|
|
removed_is_leader BOOLEAN;
|
|
BEGIN
|
|
PERFORM parties_get_exclusive_operation_lock();
|
|
|
|
DELETE FROM party_members WHERE player_id = in_player_id RETURNING player_id, party_id INTO removed_player_id, out_party_id;
|
|
|
|
IF removed_player_id IS NOT NULL THEN
|
|
-- check if there are more than 1 player in the party
|
|
SELECT INTO member_count COUNT(*) FROM party_members WHERE party_id = out_party_id;
|
|
IF member_count > 1 THEN
|
|
-- check if removed player is leader
|
|
SELECT INTO removed_is_leader EXISTS (SELECT 1 FROM parties WHERE party_leader_id = removed_player_id);
|
|
IF removed_is_leader THEN
|
|
-- TODO promote player other player
|
|
PERFORM promote_new_party_leader(out_party_id);
|
|
END IF;
|
|
END IF;
|
|
|
|
SELECT accounts.platform_name INTO out_player_platform_name FROM accounts
|
|
JOIN actors ON actors.id = in_player_id
|
|
WHERE accounts.id = actors.owner_account_id;
|
|
|
|
SELECT num_of_players INTO out_platform_members_count FROM platform_parties_mapping WHERE platform_name = out_player_platform_name AND dune_party_id = out_party_id;
|
|
IF out_platform_members_count IS NOT NULL THEN
|
|
-- there was a platform session for the player's party
|
|
IF out_platform_members_count <= 1 THEN
|
|
-- if player leaving causes no players to be in that platform session anymore, remove entry
|
|
DELETE FROM platform_parties_mapping WHERE platform_name = out_player_platform_name AND dune_party_id = out_party_id;
|
|
ELSE
|
|
-- still players, decrease platform player count
|
|
UPDATE platform_parties_mapping SET num_of_players = out_platform_members_count-1 WHERE platform_name = out_player_platform_name AND dune_party_id = out_party_id;
|
|
END IF;
|
|
END IF;
|
|
|
|
PERFORM pg_notify('party_notify_channel', format(
|
|
'remove_party_member#{"PlayerId" : %s, "PartyId" : %s, "PlayerPlatformName" : "%s", "PartyRemoveReason" : %s}',
|
|
removed_player_id, out_party_id, out_player_platform_name, in_remove_reason));
|
|
|
|
If member_count <= 1 THEN
|
|
PERFORM disband_party(out_party_id);
|
|
END IF;
|
|
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- remove_recipes_from_actor_properties(recipes_to_remove text[]) -> void
|
|
-- oid: 58525 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_recipes_from_actor_properties(recipes_to_remove text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
with actors_properties as (
|
|
select id, properties->'CraftingRecipesLibraryActorComponent'->'m_KnownItemRecipes' as recipes
|
|
from actors
|
|
),
|
|
modified_actors_properties as (
|
|
select id, (
|
|
select jsonb_agg(recipe)
|
|
from jsonb_array_elements(actors_properties.recipes) as recipe
|
|
where not (recipe->'BaseRecipeId'->>'Name' = any(recipes_to_remove))
|
|
) as filtered_recipes
|
|
from actors_properties
|
|
)
|
|
update actors
|
|
set properties = jsonb_set(
|
|
actors.properties,
|
|
'{CraftingRecipesLibraryActorComponent,m_KnownItemRecipes}',
|
|
coalesce(modified_actors_properties.filtered_recipes, '[]'::jsonb)
|
|
)
|
|
from modified_actors_properties
|
|
where actors.id = modified_actors_properties.id;
|
|
end;
|
|
$function$
|
|
|
|
|
|
-- remove_resourcefield_states(in_map text, in_dimension_index integer, in_field_ids bigint[]) -> void
|
|
-- oid: 58526 kind: FUNCTION category: items_purge
|
|
|
|
CREATE OR REPLACE FUNCTION dune.remove_resourcefield_states(in_map text, in_dimension_index integer, in_field_ids bigint[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE
|
|
FROM resourcefield_state
|
|
WHERE field_id = ANY(in_field_ids) AND map = in_map AND dimension_index = in_dimension_index;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- request_spawn_spice_field(in_server_id text, in_spicefield_type_id integer) -> void
|
|
-- oid: 58527 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.request_spawn_spice_field(in_server_id text, in_spicefield_type_id integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM spicefield_type_id FROM spicefield_types AS t
|
|
WHERE t.spicefield_type_id = in_spicefield_type_id AND t.is_spawning_active IS TRUE AND t.current_globally_primed < t.max_globally_primed AND t.current_globally_active < t.max_globally_active;
|
|
IF NOT FOUND THEN
|
|
RETURN;
|
|
END IF;
|
|
|
|
UPDATE spicefield_server_availability
|
|
SET requested_spawned_of_type = requested_spawned_of_type + 1
|
|
WHERE server_id = in_server_id AND spicefield_type_id = in_spicefield_type_id;
|
|
END; $function$
|
|
|
|
|
|
-- reset_all_players_from_server_ids_grace_period_and_logoff_timer(in_server_id text, in_reset_time timestamp without time zone) -> void
|
|
-- oid: 58528 kind: FUNCTION category: cleanup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.reset_all_players_from_server_ids_grace_period_and_logoff_timer(in_server_id text, in_reset_time timestamp without time zone)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE encrypted_player_state SET reconnect_grace_period_end = in_reset_time WHERE server_id = in_server_id AND reconnect_grace_period_end > in_reset_time;
|
|
UPDATE encrypted_player_state SET logoff_persistence_end_time = in_reset_time WHERE server_id = in_server_id AND logoff_persistence_end_time > in_reset_time;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- reset_global_spice_field_state(in_map_name text, in_dimension_index integer) -> void
|
|
-- oid: 58529 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.reset_global_spice_field_state(in_map_name text, in_dimension_index integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE spicefield_server_availability sa
|
|
SET requested_spawned_of_type = 0
|
|
FROM spicefield_types st
|
|
WHERE sa.spicefield_type_id = st.spicefield_type_id AND st.map_name = in_map_name AND st.dimension_index = in_dimension_index;
|
|
|
|
UPDATE spicefield_types
|
|
SET current_globally_primed = 0, current_globally_active = 0
|
|
WHERE map_name = in_map_name AND dimension_index = in_dimension_index;
|
|
END; $function$
|
|
|
|
|
|
-- reset_journey_story_nodes_for_player(in_player_id text, in_story_node_ids text[]) -> void
|
|
-- oid: 58530 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.reset_journey_story_nodes_for_player(in_player_id text, in_story_node_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF NOT is_player_offline(in_player_id) THEN
|
|
RAISE EXCEPTION 'Cannot execute query because the player is online - they must be offline in order for the journey data to be updated correctly without risking it being overwritten by player actions.';
|
|
END IF;
|
|
|
|
UPDATE journey_story_node
|
|
SET complete_condition_state = jsonb_object(ARRAY[]::text[])
|
|
WHERE story_node_id = ANY(in_story_node_ids)
|
|
AND account_id IN (
|
|
SELECT id
|
|
FROM accounts a
|
|
WHERE a.user = in_player_id
|
|
);
|
|
|
|
DELETE FROM journey_story_node_cooldown
|
|
WHERE story_node_id = ANY(in_story_node_ids)
|
|
AND account_id IN (
|
|
SELECT id
|
|
FROM accounts a
|
|
WHERE a.user = in_player_id
|
|
);
|
|
END $function$
|
|
|
|
|
|
-- reset_server_all_player_access_codes(in_account_id bigint) -> void
|
|
-- oid: 58531 kind: FUNCTION category: cleanup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.reset_server_all_player_access_codes(in_account_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM player_access_codes
|
|
WHERE account_id = in_account_id
|
|
AND is_resettable = true;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- reset_specialization_keystones(in_player_id bigint) -> void
|
|
-- oid: 58532 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.reset_specialization_keystones(in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM purchased_specialization_keystones WHERE player_id = in_player_id;
|
|
END $function$
|
|
|
|
|
|
-- reset_specialization_tracks(in_player_id bigint) -> void
|
|
-- oid: 58533 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.reset_specialization_tracks(in_player_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM specialization_tracks WHERE player_id = in_player_id;
|
|
END $function$
|
|
|
|
|
|
-- restore_backup_vehicle(in_account_id bigint, in_server_info dune.serverinfo, in_transform dune.transform) -> bigint
|
|
-- oid: 58534 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.restore_backup_vehicle(in_account_id bigint, in_server_info dune.serverinfo, in_transform dune.transform)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_vehicle_id BIGINT;
|
|
BEGIN
|
|
-- Retrieve a backup vehicle for the provided account.
|
|
SELECT vehicle_id INTO found_vehicle_id
|
|
FROM backup_vehicles
|
|
WHERE account_id = in_account_id
|
|
LIMIT 1; -- In case more than one is stored.
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'No backup vehicle found for account_id: %', in_account_id;
|
|
END IF;
|
|
|
|
-- Only restore vehicle if the actor state is vehicle backup
|
|
PERFORM 1 FROM actor_state WHERE actor_id = found_vehicle_id AND state = 'VehicleBackup';
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trying to restore vehicle % that does not belong to vehicle backup feature.', found_vehicle_id;
|
|
END IF;
|
|
|
|
-- Update the actors record to restore the vehicle.
|
|
UPDATE actors
|
|
SET map = in_server_info.map,
|
|
partition_id = in_server_info.partition_id,
|
|
dimension_index = in_server_info.dimension_index,
|
|
transform = in_transform
|
|
WHERE id = found_vehicle_id;
|
|
IF NOT FOUND THEN
|
|
RAISE WARNING 'No actor record found with id % during restore.', found_vehicle_id;
|
|
END IF;
|
|
|
|
-- Remove the restored vehicle from backup_vehicles.
|
|
DELETE FROM backup_vehicles WHERE vehicle_id = found_vehicle_id;
|
|
RAISE INFO 'Deleted backup record for vehicle %.', found_vehicle_id;
|
|
|
|
-- There is no need to keep the actor state in the table anymore since the vehicle backup was successful data wise
|
|
DELETE FROM actor_state WHERE actor_id = found_vehicle_id;
|
|
RAISE INFO 'Deleted actor state for vehicle %.', found_vehicle_id;
|
|
|
|
PERFORM verify_item_dup_backup_tool(in_account_id, found_vehicle_id, 'item_dup_on_restore_vbt');
|
|
|
|
RETURN found_vehicle_id;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- restore_recovered_vehicle(in_account_id bigint, in_vehicle_id bigint, in_server_info dune.serverinfo, in_transform dune.transform, in_restore_time_limit integer) -> void
|
|
-- oid: 58535 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.restore_recovered_vehicle(in_account_id bigint, in_vehicle_id bigint, in_server_info dune.serverinfo, in_transform dune.transform, in_restore_time_limit integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_vehicle_id BIGINT;
|
|
found_vehicle_name TEXT;
|
|
found_player_id BIGINT;
|
|
BEGIN
|
|
-- Retrieve a recovered vehicle for the provided account.
|
|
SELECT vehicle_id, vehicle_name INTO found_vehicle_id, found_vehicle_name
|
|
FROM recovered_vehicles
|
|
WHERE account_id = in_account_id AND vehicle_id = in_vehicle_id
|
|
-- 60s leeway in favor of player in case they try to restore last second
|
|
AND (migrated = TRUE OR time_stored > NOW() - (in_restore_time_limit + 60) * INTERVAL '1 second')
|
|
LIMIT 1; -- In case more than one is stored.
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'No recovered vehicle found for account_id: % and vehicle_id: %', in_account_id, in_vehicle_id;
|
|
END IF;
|
|
|
|
-- Only restore vehicle if the actor state is VehicleRecovery
|
|
PERFORM 1 FROM actor_state WHERE actor_id = found_vehicle_id AND state = 'VehicleRecovery';
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Trying to restore vehicle % that does not belong to vehicle recovery feature.', found_vehicle_id;
|
|
END IF;
|
|
|
|
-- Update the actors record to restore the vehicle.
|
|
UPDATE actors
|
|
SET map = in_server_info.map,
|
|
partition_id = in_server_info.partition_id,
|
|
dimension_index = in_server_info.dimension_index,
|
|
transform = in_transform
|
|
WHERE id = found_vehicle_id;
|
|
IF NOT FOUND THEN
|
|
RAISE WARNING 'No actor record found with id % during restore.', found_vehicle_id;
|
|
END IF;
|
|
|
|
-- permissions use the player controllers id, so we need to get that from the account id
|
|
SELECT player_controller_id INTO found_player_id FROM player_state WHERE account_id = in_account_id LIMIT 1;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'No player_controller_id found for account: %', in_account_id;
|
|
END IF;
|
|
|
|
-- restore default permissions
|
|
INSERT INTO permission_actor("actor_id", "actor_name", "actor_type", "access_level", "is_child")
|
|
VALUES(found_vehicle_id, found_vehicle_name, 2, 3, false);
|
|
|
|
INSERT INTO permission_actor_rank("permission_actor_id", "player_id", "rank")
|
|
VALUES(found_vehicle_id, found_player_id, 1);
|
|
|
|
-- Remove the restored vehicle from recovered_vehicles.
|
|
DELETE FROM recovered_vehicles WHERE vehicle_id = found_vehicle_id;
|
|
RAISE INFO 'Deleted recovery record for vehicle %.', found_vehicle_id;
|
|
|
|
-- There is no need to keep the actor state in the table anymore since the vehicle recovery was successful data wise
|
|
DELETE FROM actor_state WHERE actor_id = found_vehicle_id;
|
|
RAISE INFO 'Deleted actor state for vehicle %.', found_vehicle_id;
|
|
|
|
--PERFORM verify_item_dup_backup_tool(in_account_id, found_vehicle_id, 'item_dup_on_restore_vbt');
|
|
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- retrieve_all_static_shifting_sand() -> TABLE(out_id text, out_alpha double precision, out_x double precision, out_y double precision, out_last_modified_time bigint)
|
|
-- oid: 58536 kind: FUNCTION category: shifting_sand
|
|
|
|
CREATE OR REPLACE FUNCTION dune.retrieve_all_static_shifting_sand()
|
|
RETURNS TABLE(out_id text, out_alpha double precision, out_x double precision, out_y double precision, out_last_modified_time bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT id, alpha, x, y, EXTRACT(EPOCH FROM last_modified_time)::BIGINT AS last_modified_time FROM shiftingsands_data;
|
|
END; $function$
|
|
|
|
|
|
-- returning_player_award_given(in_account_id bigint) -> void
|
|
-- oid: 58537 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.returning_player_award_given(in_account_id bigint)
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
UPDATE player_state SET last_returning_player_awarded_time=now(), last_returning_player_event_time=NULL WHERE account_id=in_account_id;
|
|
$function$
|
|
|
|
|
|
-- reveal_journey_story_nodes_for_player(in_player_id text, in_story_node_ids text[]) -> void
|
|
-- oid: 58538 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.reveal_journey_story_nodes_for_player(in_player_id text, in_story_node_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF NOT is_player_offline(in_player_id) THEN
|
|
RAISE EXCEPTION 'Cannot execute query because the player is online - they must be offline in order for the journey data to be updated correctly without risking it being overwritten by player actions.';
|
|
END IF;
|
|
|
|
WITH player_account_id AS (
|
|
SELECT id
|
|
FROM accounts a
|
|
WHERE a.user = in_player_id
|
|
)
|
|
INSERT INTO journey_story_node(account_id, story_node_id, override_reward_block, has_pending_reward, complete_condition_state, reveal_condition_state, fail_condition_state, metadata_state, reset_group)
|
|
SELECT player_account_id.id, completed_node.story_node_id, completed_node.override_reward_block, completed_node.has_pending_reward, completed_node.complete_condition_state, completed_node.reveal_condition_state, completed_node.fail_condition_state, completed_node.metadata_state, completed_node.reset_group
|
|
FROM player_account_id
|
|
CROSS JOIN (
|
|
SELECT story_node_id, false, false, jsonb_object(ARRAY[]::text[]), to_jsonb(true), jsonb_object(ARRAY[]::text[]), jsonb_object(ARRAY[]::text[]), 'Default'::JourneyStoryResetGroup
|
|
FROM UNNEST(in_story_node_ids) AS story_node_id
|
|
) completed_node(story_node_id, override_reward_block, has_pending_reward, complete_condition_state, reveal_condition_state, fail_condition_state, metadata_state, reset_group)
|
|
ON CONFLICT ON CONSTRAINT journey_story_node_pkey
|
|
DO UPDATE SET
|
|
reveal_condition_state = EXCLUDED.reveal_condition_state,
|
|
metadata_state = EXCLUDED.metadata_state;
|
|
END $function$
|
|
|
|
|
|
-- save_aborted_authority_transfer_actors(in_actor_ids bigint[], in_partition_id bigint) -> void
|
|
-- oid: 58539 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_aborted_authority_transfer_actors(in_actor_ids bigint[], in_partition_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO actor_state(actor_id, state)
|
|
SELECT a.id, 'AbortedAuthorityTransfer'
|
|
FROM actors AS a
|
|
WHERE a.id = ANY(in_actor_ids) AND a.partition_id = in_partition_id
|
|
ON CONFLICT DO NOTHING;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- save_actor_dislocation(in_actor_id bigint, in_current_server_info dune.serverinfo, in_target_location dune.vector, in_target_dimension_index integer) -> void
|
|
-- oid: 58540 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_actor_dislocation(in_actor_id bigint, in_current_server_info dune.serverinfo, in_target_location dune.vector, in_target_dimension_index integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
update actors
|
|
set
|
|
transform = (in_target_location, (transform).rotation),
|
|
dimension_index = in_target_dimension_index,
|
|
partition_id = null
|
|
where id = in_actor_id
|
|
and map = (in_current_server_info).map
|
|
and dimension_index = (in_current_server_info).dimension_index
|
|
and (
|
|
partition_id is null
|
|
or (in_current_server_info).partition_id is null
|
|
or partition_id = (in_current_server_info).partition_id
|
|
);
|
|
end
|
|
$function$
|
|
|
|
|
|
-- save_actors(in_server_info dune.serverinfo, in_actors dune.actordescription[], in_actor_state dune.actorstate) -> TABLE(actor_id bigint, current_saved_serial bigint, saved boolean)
|
|
-- oid: 58541 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_actors(in_server_info dune.serverinfo, in_actors dune.actordescription[], in_actor_state dune.actorstate DEFAULT 'Default'::dune.actorstate)
|
|
RETURNS TABLE(actor_id bigint, current_saved_serial bigint, saved boolean)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return query with
|
|
input_actors as (
|
|
select * from unnest(in_actors)
|
|
),
|
|
valid_input_actors as (
|
|
select input_actors.id from input_actors
|
|
left join actor_state on input_actors.id = actor_state.actor_id
|
|
where actor_state.state = in_actor_state or (in_actor_state = 'Default' and actor_state.actor_id is null)
|
|
),
|
|
serial_checks as (
|
|
select
|
|
input.id,
|
|
input.serial as input_serial,
|
|
coalesce(actors.serial, 0) as saved_serial,
|
|
input.serial >= coalesce(actors.serial, 0) and input.id in (select id from valid_input_actors) as should_save
|
|
from
|
|
input_actors as input left join actors using (id)
|
|
),
|
|
actors_to_save as (
|
|
select i.* from input_actors as i join serial_checks as c using (id) where c.should_save
|
|
),
|
|
upsert_actors as (
|
|
insert into actors(
|
|
"id", "class", "transform",
|
|
"gas_attributes",
|
|
"properties",
|
|
"map", "partition_id", "dimension_index",
|
|
"serial"
|
|
)
|
|
select
|
|
i.id, i.class_name, i.transform,
|
|
(i.generic_data).gas_attribute_sets_json, (i.generic_data).properties_json,
|
|
in_server_info.map, in_server_info.partition_id, coalesce(in_server_info.dimension_index, 0),
|
|
i.serial
|
|
from actors_to_save as i
|
|
on conflict (id) do update
|
|
set
|
|
"class" = EXCLUDED.class, "transform" = case when EXCLUDED.transform is null or (EXCLUDED.transform).location = (zero_transform()).location then actors.transform else EXCLUDED.transform end,
|
|
|
|
"gas_attributes" = EXCLUDED.gas_attributes, "properties" = EXCLUDED.properties,
|
|
|
|
"map" = EXCLUDED.map, "partition_id" = EXCLUDED.partition_id, "dimension_index" = EXCLUDED.dimension_index,
|
|
"serial" = EXCLUDED.serial
|
|
returning id
|
|
),
|
|
fgl_entity_data as (
|
|
select id as actor_id, (u).entity_id, (u).slot_name, (u).components_json as components
|
|
from (select id, unnest((generic_data).entities) as u from actors_to_save) q
|
|
),
|
|
missing_entities as (
|
|
select entity_id
|
|
from actors_to_save join actor_fgl_entities as existing on (actors_to_save.id = existing.actor_id)
|
|
where not exists(select 1 from fgl_entity_data as updated where updated.entity_id=existing.entity_id)
|
|
),
|
|
delete_missing_entity_links as (
|
|
delete from actor_fgl_entities as existing using missing_entities
|
|
where existing.entity_id=missing_entities.entity_id
|
|
returning existing.entity_id as deleted_entity_id
|
|
),
|
|
delete_missing_entities as (
|
|
delete from fgl_entities as existing using missing_entities
|
|
where existing.entity_id=missing_entities.entity_id
|
|
),
|
|
upsert_entities as (
|
|
insert into fgl_entities("entity_id", "components")
|
|
select entity_id, components from fgl_entity_data
|
|
on conflict (entity_id) do update
|
|
set components=EXCLUDED.components
|
|
returning entity_id
|
|
),
|
|
upsert_entity_links as (
|
|
insert into actor_fgl_entities("actor_id", "entity_id", "slot_name")
|
|
select fgl_entity_data.actor_id, fgl_entity_data.entity_id, fgl_entity_data.slot_name
|
|
from fgl_entity_data left join upsert_entities using (entity_id)
|
|
-- HACK: this is a temporary fix until we do TECH-23063
|
|
where not entity_id in (select deleted_entity_id from delete_missing_entity_links)
|
|
on conflict (entity_id) do update
|
|
set
|
|
actor_id=EXCLUDED.actor_id,
|
|
slot_name=EXCLUDED.slot_name
|
|
returning actor_fgl_entities.actor_id, actor_fgl_entities.entity_id
|
|
),
|
|
all_actor_entities as (
|
|
select fgl_entity_data.actor_id as id, array_agg(entity_id) as entity_ids
|
|
from fgl_entity_data
|
|
left join upsert_entities using (entity_id)
|
|
left join upsert_entity_links using (entity_id)
|
|
group by fgl_entity_data.actor_id
|
|
),
|
|
extra_data as (
|
|
select
|
|
input_actors.id,
|
|
serial_checks.saved_serial,
|
|
(serial_checks.should_save) as saved,
|
|
(input_actors.generic_data).building_actor_data as building_data,
|
|
(input_actors.generic_data).placeable_actor_data as placeable_data,
|
|
(input_actors.generic_data).totem_actor_data as totem_data,
|
|
coalesce(all_actor_entities.entity_ids, array[]::int[]) as entity_ids
|
|
from
|
|
serial_checks
|
|
left join input_actors using(id)
|
|
left join upsert_actors using(id) -- this is needed for dependency
|
|
left join all_actor_entities using(id) -- this is needed for dependency only
|
|
),
|
|
save_extras as (
|
|
select
|
|
extra_data.id,
|
|
extra_data.saved_serial,
|
|
extra_data.saved,
|
|
case when extra_data.saved and building_data is not null then
|
|
save_building(id, building_data)
|
|
end,
|
|
case when extra_data.saved and placeable_data is not null then
|
|
save_placeable(id, placeable_data)
|
|
end,
|
|
case when extra_data.saved and totem_data is not null then
|
|
save_totem(id, totem_data)
|
|
end,
|
|
entity_ids
|
|
from extra_data
|
|
)
|
|
select id, saved_serial, save_extras.saved from save_extras;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- save_building(in_building_id bigint, in_data dune.buildingsavedata) -> void
|
|
-- oid: 58543 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_building(in_building_id bigint, in_data dune.buildingsavedata)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
instance BUILDINGINSTANCE;
|
|
instance_to_remove INTEGER;
|
|
instance_owner BuildingInstanceUpdateOwner;
|
|
BEGIN
|
|
-- ADD
|
|
IF array_length(in_data.in_add_building_data, 1) > 0 THEN
|
|
INSERT INTO building_instances(
|
|
"building_id",
|
|
"instance_id",
|
|
"building_type",
|
|
"transform",
|
|
"owner_entity_id",
|
|
"building_flags",
|
|
"health",
|
|
"shelter",
|
|
"stabilization_begin_timespan",
|
|
"stabilization_end_timespan",
|
|
"stabilization_state",
|
|
"sand_buildup"
|
|
)
|
|
SELECT
|
|
in_building_id,
|
|
add_data.instance_id,
|
|
add_data.building_type,
|
|
add_data.transform,
|
|
_building_validate_totem_owner_id(add_data.owner_entity_id),
|
|
add_data.building_flags,
|
|
add_data.health,
|
|
add_data.shelter,
|
|
add_data.stabilization_begin_timespan,
|
|
add_data.stabilization_end_timespan,
|
|
add_data.stabilization_state,
|
|
add_data.sand_buildup
|
|
FROM unnest(in_data.in_add_building_data) as add_data
|
|
ON CONFLICT ("building_id", "instance_id")
|
|
DO UPDATE SET
|
|
"building_type" = (instance).building_type,
|
|
"transform" = (instance).transform,
|
|
"owner_entity_id" = _building_validate_totem_owner_id((instance).owner_entity_id),
|
|
"building_flags" = (instance).building_flags,
|
|
"health" = (instance).health,
|
|
"shelter" = (instance).shelter,
|
|
"stabilization_begin_timespan" = (instance).stabilization_begin_timespan,
|
|
"stabilization_end_timespan" = (instance).stabilization_end_timespan,
|
|
"stabilization_state" = (instance).stabilization_state,
|
|
"sand_buildup" = (instance).sand_buildup;
|
|
END IF;
|
|
|
|
-- REMOVE
|
|
IF array_length(in_data.in_remove_building_data, 1) > 0 THEN
|
|
DELETE FROM building_instances
|
|
WHERE building_instances."building_id" = in_building_id AND building_instances."instance_id" = ANY(in_data.in_remove_building_data);
|
|
END IF;
|
|
|
|
-- OWNER. 99.99% of the time, this will only have 1 Owner Array.
|
|
IF array_length(in_data.in_building_owner_data, 1) > 0 THEN
|
|
FOREACH instance_owner IN ARRAY in_data.in_building_owner_data LOOP
|
|
WITH owner_changes_table AS
|
|
(
|
|
SELECT unnest(instance_owner.instances) AS instance_id, instance_owner.owner_entity_id AS owner_entity_id
|
|
)
|
|
UPDATE building_instances
|
|
SET owner_entity_id = _building_validate_totem_owner_id(owner_changes_table.owner_entity_id)
|
|
FROM owner_changes_table
|
|
WHERE building_instances.building_id = in_building_id AND building_instances.instance_id = owner_changes_table.instance_id;
|
|
END LOOP;
|
|
END IF;
|
|
|
|
-- STABILIZATION
|
|
IF array_length(in_data.in_building_stabilization_data, 1) > 0 THEN
|
|
WITH stabilization_changes_table AS
|
|
(
|
|
select * FROM unnest(in_data.in_building_stabilization_data)
|
|
)
|
|
UPDATE building_instances SET stabilization_begin_timespan = stabilization_changes_table.stabilization_begin_timespan, stabilization_end_timespan = stabilization_changes_table.stabilization_end_timespan, stabilization_state = stabilization_changes_table.stabilization_state
|
|
FROM stabilization_changes_table
|
|
WHERE building_instances.building_id = in_building_id AND building_instances.instance_id = stabilization_changes_table.instance_id;
|
|
END IF;
|
|
|
|
-- HEALTH
|
|
IF array_length(in_data.in_building_health_data, 1) > 0 THEN
|
|
WITH health_changes_table AS
|
|
(
|
|
select * FROM unnest(in_data.in_building_health_data)
|
|
)
|
|
UPDATE building_instances SET health = health_changes_table.health
|
|
FROM health_changes_table
|
|
WHERE building_instances.building_id = in_building_id AND building_instances.instance_id = health_changes_table.instance_id;
|
|
END IF;
|
|
|
|
-- SHELTER
|
|
IF array_length(in_data.in_building_shelter_data, 1) > 0 THEN
|
|
WITH shelter_changes_table AS
|
|
(
|
|
select * FROM unnest(in_data.in_building_shelter_data)
|
|
)
|
|
UPDATE building_instances SET shelter = shelter_changes_table.shelter
|
|
FROM shelter_changes_table
|
|
WHERE building_instances.building_id = in_building_id AND building_instances.instance_id = shelter_changes_table.instance_id;
|
|
END IF;
|
|
|
|
-- SAND BUILDUP
|
|
IF array_length(in_data.in_building_sand_buildup_data, 1) > 0 THEN
|
|
WITH sand_buildup_changes_table AS
|
|
(
|
|
select * FROM unnest(in_data.in_building_sand_buildup_data)
|
|
)
|
|
UPDATE building_instances SET sand_buildup = sand_buildup_changes_table.sand_buildup
|
|
FROM sand_buildup_changes_table
|
|
WHERE building_instances.building_id = in_building_id AND building_instances.instance_id = sand_buildup_changes_table.instance_id;
|
|
END IF;
|
|
|
|
-- BUILDING FLAGS
|
|
IF array_length(in_data.in_building_building_flags_data, 1) > 0 THEN
|
|
WITH building_flags_changes_table AS
|
|
(
|
|
select * FROM unnest(in_data.in_building_building_flags_data)
|
|
)
|
|
UPDATE building_instances SET building_flags = building_flags_changes_table.building_flags
|
|
FROM building_flags_changes_table
|
|
WHERE building_instances.building_id = in_building_id AND building_instances.instance_id = building_flags_changes_table.instance_id;
|
|
END IF;
|
|
|
|
-- BUILDING TRANSFORM
|
|
IF array_length(in_data.in_building_building_transform_data, 1) > 0 THEN
|
|
WITH building_flags_transform_table AS
|
|
(
|
|
select * FROM unnest(in_data.in_building_building_transform_data)
|
|
)
|
|
UPDATE building_instances SET transform = building_flags_transform_table.transform
|
|
FROM building_flags_transform_table
|
|
WHERE building_instances.building_id = in_building_id AND building_instances.instance_id = building_flags_transform_table.instance_id;
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- save_building_blueprint_copy(in_building_item_id bigint, in_building_blueprint_id bigint, in_building_blueprint_building_data dune.buildingblueprintpiecesaveitemcontainer[], in_building_blueprint_placeable_data dune.buildingblueprintplaceablesaveitemcontainer[], in_building_blueprint_pentashield_data dune.buildingblueprintpentashielditem[]) -> bigint
|
|
-- oid: 58544 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_building_blueprint_copy(in_building_item_id bigint, in_building_blueprint_id bigint, in_building_blueprint_building_data dune.buildingblueprintpiecesaveitemcontainer[], in_building_blueprint_placeable_data dune.buildingblueprintplaceablesaveitemcontainer[], in_building_blueprint_pentashield_data dune.buildingblueprintpentashielditem[])
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
return_id BIGINT;
|
|
BEGIN
|
|
IF in_building_blueprint_id != 0 THEN
|
|
DELETE FROM building_blueprints WHERE id = in_building_blueprint_id;
|
|
END IF;
|
|
|
|
INSERT INTO building_blueprints(id, item_id, player_id, building_blueprint_map)
|
|
VALUES(DEFAULT, in_building_item_id, NULL, '') RETURNING id INTO return_id;
|
|
|
|
-- All Building Pieces
|
|
INSERT INTO building_blueprint_instances(building_blueprint_id, instance_id, building_type, transform, provides_stability, health, hologram)
|
|
SELECT
|
|
return_id,
|
|
piece_data.instance_id,
|
|
container_data.building_type,
|
|
piece_data.transform,
|
|
piece_data.provides_stability,
|
|
piece_data.health,
|
|
True
|
|
FROM
|
|
unnest(in_building_blueprint_building_data) AS container_data
|
|
CROSS JOIN LATERAL unnest(container_data.building_pieces) AS piece_data;
|
|
|
|
-- All Placeables
|
|
INSERT INTO building_blueprint_placeables(building_blueprint_id, placeable_id, building_type, transform, hologram)
|
|
SELECT
|
|
return_id,
|
|
placeable_data.placeable_id,
|
|
container_data.building_type,
|
|
placeable_data.transform,
|
|
True
|
|
FROM
|
|
unnest(in_building_blueprint_placeable_data) AS container_data
|
|
CROSS JOIN LATERAL unnest(container_data.placeables) AS placeable_data;
|
|
|
|
-- Pentashields
|
|
INSERT INTO building_blueprint_pentashields("building_blueprint_id", "placeable_id", "scale")
|
|
SELECT return_id as building_blueprint_id, placeable_id, scale FROM unnest(in_building_blueprint_pentashield_data);
|
|
|
|
RETURN return_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- save_demo_account_time(in_fls_id text, in_demo_playtime_seconds integer) -> void
|
|
-- oid: 58545 kind: FUNCTION category: schema_meta
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_demo_account_time(in_fls_id text, in_demo_playtime_seconds integer)
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
INSERT INTO demo_users("fls_id", "demo_playtime_seconds", "demo_state")
|
|
VALUES (in_fls_id, in_demo_playtime_seconds, 'Demo'::DemoState)
|
|
ON CONFLICT ("fls_id") DO UPDATE
|
|
SET demo_playtime_seconds = EXCLUDED.demo_playtime_seconds;
|
|
$function$
|
|
|
|
|
|
-- save_dialogue_data(in_player_controller_id bigint, in_met_npcs text[], in_taken_nodes integer[]) -> void
|
|
-- oid: 58546 kind: FUNCTION category: dialogue
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_dialogue_data(in_player_controller_id bigint, in_met_npcs text[], in_taken_nodes integer[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO dialogue_met_npcs(player_id, npc_name) SELECT in_player_controller_id, unnest(in_met_npcs)
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
INSERT INTO dialogue_taken_nodes(player_id, node_id) SELECT in_player_controller_id, unnest(in_taken_nodes)
|
|
ON CONFLICT DO NOTHING;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- save_item(in_item dune.inventoryitem) -> void
|
|
-- oid: 58547 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_item(in_item dune.inventoryitem)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
INSERT INTO
|
|
items (id, inventory_id, stack_size, quality_level, volume_override, position_index, template_id, stats, is_new, acquisition_time)
|
|
VALUES (
|
|
(in_item).item_id,
|
|
(in_item).inventory_id,
|
|
(in_item).stack_size,
|
|
(in_item).quality_level,
|
|
(in_item).volume_override,
|
|
(in_item).position_index,
|
|
(in_item).template_id,
|
|
(in_item).stats,
|
|
(in_item).is_new,
|
|
(in_item).acquisition_time
|
|
)
|
|
ON CONFLICT (id)
|
|
DO UPDATE SET
|
|
inventory_id = (in_item).inventory_id,
|
|
stack_size = (in_item).stack_size,
|
|
quality_level = (in_item).quality_level,
|
|
volume_override = (in_item).volume_override,
|
|
position_index = (in_item).position_index,
|
|
template_id = (in_item).template_id,
|
|
stats = items.stats || (in_item).stats,
|
|
is_new = (in_item).is_new,
|
|
acquisition_time = (in_item).acquisition_time;
|
|
|
|
-- log item tracking
|
|
PERFORM _add_item_trace_log('save_item', (in_item).item_id, (in_item).inventory_id, (in_item).template_id, (in_item).position_index);
|
|
end
|
|
$function$
|
|
|
|
|
|
-- save_journey_story_node(in_account_id bigint, in_story_node_id text, in_override_reward_block boolean, in_has_pending_reward boolean, in_complete_condition_state jsonb, in_reveal_condition_state jsonb, in_fail_condition_state jsonb, in_metadata_state jsonb, in_reset_group dune.journeystoryresetgroup) -> void
|
|
-- oid: 58548 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_journey_story_node(in_account_id bigint, in_story_node_id text, in_override_reward_block boolean, in_has_pending_reward boolean, in_complete_condition_state jsonb, in_reveal_condition_state jsonb, in_fail_condition_state jsonb, in_metadata_state jsonb, in_reset_group dune.journeystoryresetgroup)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO journey_story_node(account_id, story_node_id, override_reward_block, has_pending_reward, complete_condition_state, reveal_condition_state, fail_condition_state, metadata_state, reset_group)
|
|
VALUES(in_account_id, in_story_node_id, in_override_reward_block, in_has_pending_reward, in_complete_condition_state, in_reveal_condition_state, in_fail_condition_state, in_metadata_state, in_reset_group)
|
|
ON CONFLICT (account_id, story_node_id)
|
|
DO UPDATE SET
|
|
override_reward_block = in_override_reward_block,
|
|
has_pending_reward = in_has_pending_reward,
|
|
complete_condition_state = in_complete_condition_state,
|
|
reveal_condition_state = in_reveal_condition_state,
|
|
fail_condition_state = in_fail_condition_state,
|
|
metadata_state = in_metadata_state,
|
|
reset_group = in_reset_group;
|
|
END $function$
|
|
|
|
|
|
-- save_journey_story_nodes(in_account_id bigint, in_journey_data dune.savejourneydata[]) -> void
|
|
-- oid: 58549 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_journey_story_nodes(in_account_id bigint, in_journey_data dune.savejourneydata[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO journey_story_node(account_id, story_node_id, override_reward_block, has_pending_reward, complete_condition_state, reveal_condition_state, fail_condition_state, metadata_state, reset_group)
|
|
SELECT in_account_id, story_node_id, override_reward_block, has_pending_reward, to_jsonb(completion_state_string), to_jsonb(reveal_state_string), to_jsonb(fail_state_string), to_jsonb(metadata_state_string), reset_group
|
|
FROM UNNEST(in_journey_data)
|
|
ON CONFLICT ON CONSTRAINT journey_story_node_pkey
|
|
DO UPDATE SET
|
|
override_reward_block = EXCLUDED.override_reward_block,
|
|
has_pending_reward = EXCLUDED.has_pending_reward,
|
|
complete_condition_state = EXCLUDED.complete_condition_state,
|
|
reveal_condition_state = EXCLUDED.reveal_condition_state,
|
|
fail_condition_state = EXCLUDED.fail_condition_state,
|
|
metadata_state = EXCLUDED.metadata_state,
|
|
reset_group = EXCLUDED.reset_group;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- save_login_target_dimension(in_fls_id text, in_login_target_dimension_index integer) -> void
|
|
-- oid: 58550 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_login_target_dimension(in_fls_id text, in_login_target_dimension_index integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO player_travel_state (fls_id, login_target_dimension_index)
|
|
VALUES (in_fls_id, in_login_target_dimension_index)
|
|
ON CONFLICT (fls_id) DO UPDATE
|
|
SET login_target_dimension_index = EXCLUDED.login_target_dimension_index;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- save_markers(in_player_marker_data dune.saveplayermarkerdata[], in_marker_data dune.savemarkerdata[]) -> void
|
|
-- oid: 58551 kind: FUNCTION category: markers
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_markers(in_player_marker_data dune.saveplayermarkerdata[], in_marker_data dune.savemarkerdata[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
null_player_marker_map_id_count INTEGER;
|
|
null_marker_map_id_count INTEGER;
|
|
BEGIN
|
|
|
|
SELECT COUNT(*)
|
|
INTO null_player_marker_map_id_count
|
|
FROM UNNEST(in_player_marker_data) AS umd
|
|
LEFT JOIN map_names AS mn ON umd.map_name = mn.map_name
|
|
WHERE mn.map_name_id IS NULL; -- Find map name that doesn't exist
|
|
|
|
IF null_player_marker_map_id_count > 0 THEN
|
|
RAISE EXCEPTION 'Found records with NULL map name id for player markers!';
|
|
END IF;
|
|
|
|
SELECT COUNT(*)
|
|
INTO null_marker_map_id_count
|
|
FROM UNNEST(in_marker_data) AS umd
|
|
LEFT JOIN map_names AS mn ON umd.map_name = mn.map_name
|
|
WHERE mn.map_name_id IS NULL; -- Find map name that doesn't exist
|
|
|
|
IF null_marker_map_id_count > 0 THEN
|
|
RAISE EXCEPTION 'Found records with NULL map name id for markers!';
|
|
END IF;
|
|
|
|
INSERT INTO markers("marker_hash_id", "dimension_index", "map_name_id", "marker", "area_id", "area_radius", "long_range", "payload")
|
|
SELECT
|
|
umd.marker_hash_id,
|
|
umd.dimension_index,
|
|
mn.map_name_id,
|
|
umd.marker,
|
|
umd.area_id,
|
|
umd.area_radius,
|
|
umd.long_range,
|
|
umd.payload
|
|
FROM UNNEST(in_marker_data) umd JOIN map_names mn USING(map_name)
|
|
ORDER BY marker_hash_id, dimension_index, map_name_id
|
|
ON CONFLICT ON CONSTRAINT markers_pkey
|
|
DO UPDATE SET
|
|
"area_id" = EXCLUDED.area_id,
|
|
"area_radius" = EXCLUDED.area_radius,
|
|
"long_range" = EXCLUDED.long_range,
|
|
"payload" = EXCLUDED.payload;
|
|
|
|
WITH marker_data_for_existing_players AS (
|
|
SELECT
|
|
player_data.player_id,
|
|
player_data.marker_hash_id,
|
|
player_data.dimension_index,
|
|
mn.map_name_id,
|
|
player_data.discovery_level,
|
|
player_data.discovery_method,
|
|
player_data.player_payload
|
|
FROM UNNEST(in_player_marker_data) AS player_data
|
|
JOIN actors ON actors.id = player_data.player_id
|
|
JOIN map_names mn USING(map_name)
|
|
)
|
|
INSERT INTO player_markers("player_id", "marker_hash_id", "dimension_index", "map_name_id", "discovery_level", "discovery_method", "payload")
|
|
SELECT
|
|
in_data.player_id,
|
|
in_data.marker_hash_id,
|
|
in_data.dimension_index,
|
|
in_data.map_name_id,
|
|
in_data.discovery_level,
|
|
in_data.discovery_method,
|
|
in_data.player_payload
|
|
FROM marker_data_for_existing_players AS in_data, markers
|
|
WHERE markers.marker_hash_id = in_data.marker_hash_id AND markers.dimension_index = in_data.dimension_index AND markers.map_name_id = in_data.map_name_id
|
|
ORDER BY player_id, in_data.marker_hash_id, in_data.dimension_index, in_data.map_name_id -- Ordering for deadlock avoidance
|
|
ON CONFLICT ON CONSTRAINT player_markers_pkey
|
|
DO UPDATE SET
|
|
"discovery_level" = EXCLUDED.discovery_level,
|
|
"discovery_method" = EXCLUDED.discovery_method,
|
|
"payload" = EXCLUDED.payload;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- save_mnemonic_recall_lesson(in_account_id bigint, in_lesson_id text, in_lesson_state bigint, in_lesson_progress integer, in_is_new boolean) -> void
|
|
-- oid: 58552 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_mnemonic_recall_lesson(in_account_id bigint, in_lesson_id text, in_lesson_state bigint, in_lesson_progress integer, in_is_new boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO mnemonic_recall(account_id, lesson_id, lesson_state, lesson_progress, is_new)
|
|
VALUES(in_account_id, in_lesson_id, in_lesson_state, in_lesson_progress, in_is_new)
|
|
ON CONFLICT (account_id, lesson_id)
|
|
DO UPDATE SET
|
|
lesson_state = in_lesson_state,
|
|
lesson_progress = in_lesson_progress,
|
|
is_new = in_is_new;
|
|
END; $function$
|
|
|
|
|
|
-- save_placeable(in_placeable_id bigint, in_data dune.placeablesavedata) -> void
|
|
-- oid: 58561 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_placeable(in_placeable_id bigint, in_data dune.placeablesavedata)
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
BEGIN ATOMIC
|
|
INSERT INTO dune.placeables (id, owner_entity_id, health, building_type, has_hit_ground, has_buildable_support, is_hologram)
|
|
VALUES (save_placeable.in_placeable_id, dune._placeable_validate_totem_owner_id((save_placeable.in_data).in_owner_entity_id), (save_placeable.in_data).in_health, (save_placeable.in_data).in_building_type, (save_placeable.in_data).in_has_hit_ground, (save_placeable.in_data).in_has_buildable_support, (save_placeable.in_data).in_is_hologram) ON CONFLICT(id) DO UPDATE SET owner_entity_id = excluded.owner_entity_id, health = excluded.health, building_type = excluded.building_type, has_hit_ground = excluded.has_hit_ground, has_buildable_support = excluded.has_buildable_support, is_hologram = excluded.is_hologram;
|
|
END
|
|
|
|
|
|
-- save_player(in_player dune.playerdescription) -> boolean
|
|
-- oid: 58562 kind: FUNCTION category: player_persistence
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_player(in_player dune.playerdescription)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
fgl_entity FglEntity;
|
|
player_actors ActorDescription[];
|
|
all_serials_are_same Boolean;
|
|
should_save_all_actors Boolean;
|
|
BEGIN
|
|
player_actors := array[in_player.state, in_player.controller];
|
|
|
|
IF NOT in_player.pawn IS NULL THEN
|
|
foreach fgl_entity in array (in_player).pawn.generic_data.entities loop
|
|
if fgl_entity.slot_name in ('DuneCharacter', 'PersonalCrafting') and fgl_entity.components_json = '{}'::jsonb then
|
|
raise exception 'invalid player save with empty fgl state for pawn';
|
|
end if;
|
|
end loop;
|
|
player_actors := player_actors || in_player.pawn;
|
|
END IF;
|
|
|
|
with
|
|
ids_and_serials as (
|
|
select
|
|
input.serial = (in_player.controller).serial as is_matching_serial,
|
|
input.serial >= existing.serial as should_save
|
|
from unnest(player_actors) as input join actors as existing using (id)
|
|
)
|
|
select bool_and(is_matching_serial), bool_and(should_save) from ids_and_serials
|
|
into all_serials_are_same, should_save_all_actors;
|
|
|
|
IF NOT all_serials_are_same THEN
|
|
raise exception 'serial: serial mismatch between the player actors';
|
|
end if;
|
|
|
|
-- Demo time remaining
|
|
IF in_player.demo_playtime_seconds IS NOT NULL THEN
|
|
UPDATE demo_users
|
|
SET demo_playtime_seconds = in_player.demo_playtime_seconds
|
|
WHERE fls_id = (
|
|
SELECT acc.user FROM accounts AS acc
|
|
WHERE acc.id = in_player.id
|
|
);
|
|
END IF;
|
|
|
|
-- Demo state
|
|
IF in_player.demo_state IS NOT NULL THEN
|
|
UPDATE demo_users
|
|
SET demo_state = in_player.demo_state
|
|
WHERE fls_id = (
|
|
SELECT acc.user FROM accounts AS acc
|
|
WHERE acc.id = in_player.id
|
|
);
|
|
END IF;
|
|
|
|
IF NOT should_save_all_actors THEN
|
|
return false;
|
|
end if;
|
|
|
|
-- Allow saving of the player without having a player character (pawn)
|
|
PERFORM save_actors(in_player.pawn_server_info, player_actors);
|
|
|
|
PERFORM update_respawn_locations(in_player.id, (in_player.respawn_info).locations);
|
|
|
|
PERFORM update_death_location(in_player.pawn, in_player.pawn_server_info, in_player.life_state);
|
|
|
|
UPDATE player_state
|
|
SET pending_respawn_location_id=(in_player.respawn_info).pending_location_id, life_state=in_player.life_state
|
|
WHERE account_id=in_player.id;
|
|
|
|
return true;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- save_player_pawn(in_pawn dune.actordescription, in_server_info dune.serverinfo, in_life_state dune.playerlifestate) -> boolean
|
|
-- oid: 58563 kind: FUNCTION category: player_persistence
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_player_pawn(in_pawn dune.actordescription, in_server_info dune.serverinfo, in_life_state dune.playerlifestate)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
should_save_pawn BOOLEAN;
|
|
BEGIN
|
|
WITH
|
|
ids_and_serials AS (
|
|
SELECT actors.serial >= (in_pawn).serial AS should_save
|
|
FROM actors
|
|
WHERE actors.id = in_pawn.id
|
|
)
|
|
SELECT should_save FROM ids_and_serials
|
|
INTO should_save_pawn;
|
|
|
|
IF NOT should_save_pawn THEN
|
|
RETURN false;
|
|
END IF;
|
|
|
|
PERFORM save_actors(in_server_info, ARRAY[in_pawn]);
|
|
|
|
PERFORM update_death_location(in_pawn, in_server_info, in_life_state);
|
|
|
|
RETURN true;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- save_static_encounter_name(in_map_name text, in_package_name text, in_actor_name text, in_encounter_name text) -> void
|
|
-- oid: 58564 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_static_encounter_name(in_map_name text, in_package_name text, in_actor_name text, in_encounter_name text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO encounters_static(map_name, package_name, actor_name, encounter_name, waiting_for_reset)
|
|
VALUES(in_map_name, in_package_name, in_actor_name, in_encounter_name, false)
|
|
ON CONFLICT(map_name, package_name, actor_name)
|
|
DO UPDATE SET encounter_name = in_encounter_name, waiting_for_reset = false
|
|
WHERE encounters_static.map_name = in_map_name AND encounters_static.package_name = in_package_name AND encounters_static.actor_name = in_actor_name;
|
|
END; $function$
|
|
|
|
|
|
-- save_static_encounter_waiting_for_reset(in_map_name text, in_package_name text, in_actor_name text, in_waiting_for_reset boolean) -> void
|
|
-- oid: 58565 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_static_encounter_waiting_for_reset(in_map_name text, in_package_name text, in_actor_name text, in_waiting_for_reset boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE encounters_static
|
|
SET waiting_for_reset = in_waiting_for_reset
|
|
WHERE encounters_static.map_name = in_map_name AND encounters_static.package_name = in_package_name AND encounters_static.actor_name = in_actor_name;
|
|
END; $function$
|
|
|
|
|
|
-- save_totem(in_id bigint, in_data dune.totemsavedata) -> void
|
|
-- oid: 58571 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_totem(in_id bigint, in_data dune.totemsavedata)
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
BEGIN ATOMIC
|
|
INSERT INTO dune.totems (id, landclaim_vertical_level, last_backup_timestamp, landclaim_original_global_location, landclaim_original_global_yaw_rotation)
|
|
VALUES (save_totem.in_id, (save_totem.in_data).landclaim_vertical_level, (save_totem.in_data).last_backup_timestamp, (save_totem.in_data).landclaim_original_global_location, (save_totem.in_data).landclaim_original_global_yaw_rotation) ON CONFLICT(id) DO UPDATE SET landclaim_vertical_level = excluded.landclaim_vertical_level, last_backup_timestamp = excluded.last_backup_timestamp, landclaim_original_global_location = excluded.landclaim_original_global_location, landclaim_original_global_yaw_rotation = excluded.landclaim_original_global_yaw_rotation;
|
|
END
|
|
|
|
|
|
-- save_tracked_journey_cards(in_player_id bigint, in_tracked_journey_card text, in_tracked_landsraad_card text) -> void
|
|
-- oid: 58572 kind: FUNCTION category: player_persistence
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_tracked_journey_cards(in_player_id bigint, in_tracked_journey_card text, in_tracked_landsraad_card text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO journey_tracked_cards (player_id, tracked_journey_card, tracked_landsraad_card) Values(in_player_id, in_tracked_journey_card, in_tracked_landsraad_card)
|
|
ON CONFLICT(player_id) DO
|
|
UPDATE SET tracked_journey_card = in_tracked_journey_card, tracked_landsraad_card = in_tracked_landsraad_card;
|
|
END $function$
|
|
|
|
|
|
-- save_travel_return_info(in_player_controller_id bigint, in_map text, in_transform dune.transform) -> void
|
|
-- oid: 58573 kind: FUNCTION category: travel
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_travel_return_info(in_player_controller_id bigint, in_map text, in_transform dune.transform)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
insert into travel_return_info(
|
|
"player_controller_id", "map", "transform"
|
|
)
|
|
values(
|
|
in_player_controller_id, in_map, in_transform
|
|
)
|
|
on conflict (player_controller_id) do update
|
|
set
|
|
"map" = EXCLUDED.map,
|
|
"transform" = EXCLUDED.transform;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- save_vehicle_modules(in_add_list dune.vehiclemodule[], in_delete_list bigint[], in_stat_update dune.itemstatupdate[]) -> SETOF bigint
|
|
-- oid: 58574 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_vehicle_modules(in_add_list dune.vehiclemodule[], in_delete_list bigint[], in_stat_update dune.itemstatupdate[])
|
|
RETURNS SETOF bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
module VEHICLEMODULE;
|
|
stat ItemStatUpdate;
|
|
new_module_id BIGINT;
|
|
currentstat RECORD;
|
|
BEGIN
|
|
--RAISE NOTICE 'Add vehicle modules';
|
|
-- add vehicle modules
|
|
FOREACH module IN ARRAY in_add_list LOOP
|
|
INSERT INTO vehicle_modules(
|
|
"vehicle_id", "template_id", "stats"
|
|
) VALUES(
|
|
(module).vehicle_id, (module).template_id, (module).stats
|
|
) RETURNING id INTO new_module_id;
|
|
RETURN NEXT new_module_id;
|
|
END LOOP;
|
|
|
|
--RAISE NOTICE 'Delete vehicle modules';
|
|
-- delete modules
|
|
DELETE FROM vehicle_modules WHERE id = ANY(in_delete_list);
|
|
|
|
--RAISE NOTICE 'Add vehicle module stats';
|
|
-- add vehicle module stats
|
|
FOREACH stat IN ARRAY in_stat_update LOOP
|
|
UPDATE vehicle_modules SET "stats" = vehicle_modules.stats || (stat).value WHERE "id" = (stat).item_id;
|
|
END LOOP;
|
|
|
|
RETURN;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- save_world_partition(in_map_name text, in_server_id text, in_dimension_index bigint, in_partition_definition jsonb, in_blocked boolean, in_label text) -> bigint
|
|
-- oid: 58575 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.save_world_partition(in_map_name text, in_server_id text, in_dimension_index bigint, in_partition_definition jsonb, in_blocked boolean DEFAULT false, in_label text DEFAULT NULL::text)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
partition_id BIGINT;
|
|
BEGIN
|
|
LOCK TABLE world_partition; -- only one at a time, please
|
|
INSERT INTO world_partition(partition_id, server_id, map, partition_definition, dimension_index, blocked, label) VALUES(DEFAULT, in_server_id, in_map_name, in_partition_definition, in_dimension_index, in_blocked, in_label)
|
|
ON CONFLICT ("server_id", "map") DO UPDATE set partition_definition = in_partition_definition, blocked = in_blocked, label = in_label WHERE world_partition.server_id = in_server_id
|
|
RETURNING world_partition.partition_id INTO partition_id;
|
|
RETURN partition_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- server_info_match(in_actor dune.actors, in_server_info dune.serverinfo) -> boolean
|
|
-- oid: 58586 kind: FUNCTION category: server
|
|
|
|
CREATE OR REPLACE FUNCTION dune.server_info_match(in_actor dune.actors, in_server_info dune.serverinfo)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
STABLE STRICT
|
|
AS $function$
|
|
BEGIN
|
|
return in_actor.map = in_server_info.map
|
|
AND in_actor.dimension_index = in_server_info.dimension_index
|
|
AND (
|
|
in_actor.partition_id IS NULL
|
|
OR
|
|
in_server_info.partition_id IS NULL
|
|
OR
|
|
in_actor.partition_id = in_server_info.partition_id
|
|
);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- set_account_as_takeoverable(in_user_id text, in_new_user_id text) -> void
|
|
-- oid: 58587 kind: FUNCTION category: takeover
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_account_as_takeoverable(in_user_id text, in_new_user_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE accounts SET "user"=in_new_user_id, takeoverable=TRUE WHERE "user"=in_user_id;
|
|
END; $function$
|
|
|
|
|
|
-- set_all_inactive_players_in_farm_offline() -> void
|
|
-- oid: 58588 kind: FUNCTION category: farm
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_all_inactive_players_in_farm_offline()
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE player_state SET online_status = 'Offline', last_avatar_activity = current_timestamp WHERE online_status <> 'Offline' AND server_id NOT IN (SELECT * FROM active_server_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- set_battlegroup_close_date(in_close_date timestamp without time zone) -> timestamp without time zone
|
|
-- oid: 58589 kind: FUNCTION category: battlegroup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_battlegroup_close_date(in_close_date timestamp without time zone)
|
|
RETURNS timestamp without time zone
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO farm_variables (one_row, battlegroup_close_date) VALUES (true,in_close_date)
|
|
ON CONFLICT (one_row) DO UPDATE SET battlegroup_close_date = in_close_date;
|
|
RETURN (select * from get_battlegroup_close_date());
|
|
END
|
|
$function$
|
|
|
|
|
|
-- set_character_import_state(in_fls_id text, in_state dune.transferimportstate) -> void
|
|
-- oid: 58590 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_character_import_state(in_fls_id text, in_state dune.transferimportstate)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO character_transfer_imports (fls_id, last_update, transfer_state)
|
|
VALUES (in_fls_id, now(), in_state)
|
|
ON CONFLICT (fls_id) DO UPDATE
|
|
SET last_update = now(),
|
|
transfer_state = EXCLUDED.transfer_state;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- set_character_name(in_account_id bigint, in_name text) -> void
|
|
-- oid: 58591 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_character_name(in_account_id bigint, in_name text)
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
update encrypted_player_state set encrypted_character_name=encrypt_user_data(in_name) where account_id=in_account_id;
|
|
$function$
|
|
|
|
|
|
-- set_demo_state(in_user_id text, in_demo_state dune.demostate) -> void
|
|
-- oid: 58592 kind: FUNCTION category: schema_meta
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_demo_state(in_user_id text, in_demo_state dune.demostate)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE demo_users
|
|
SET demo_state = in_demo_state
|
|
WHERE fls_id = in_user_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- set_item_tracking_enabled(in_enabled boolean) -> void
|
|
-- oid: 58593 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_item_tracking_enabled(in_enabled boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM set_config('dune.item_tracking_enabled', in_enabled::TEXT, false);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- set_player_faction_reputation(in_actor_id bigint, in_faction_id smallint, in_reputation_amount integer) -> void
|
|
-- oid: 58594 kind: FUNCTION category: faction
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_player_faction_reputation(in_actor_id bigint, in_faction_id smallint, in_reputation_amount integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO player_faction_reputation (actor_id, faction_id, reputation_amount)
|
|
VALUES (in_actor_id, in_faction_id, in_reputation_amount)
|
|
ON CONFLICT (actor_id, faction_id)
|
|
DO UPDATE
|
|
SET reputation_amount = EXCLUDED.reputation_amount;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- set_players_from_server_ids_offline(in_server_ids text[]) -> void
|
|
-- oid: 58595 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_players_from_server_ids_offline(in_server_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE player_state SET online_status = 'Offline', last_avatar_activity = current_timestamp WHERE online_status <> 'Offline' AND server_id = ANY(in_server_ids);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- set_specialization_xp_and_level(in_player_id bigint, in_track_type dune.specializationtracktype, in_xp_amount integer, in_level real) -> void
|
|
-- oid: 58596 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.set_specialization_xp_and_level(in_player_id bigint, in_track_type dune.specializationtracktype, in_xp_amount integer, in_level real)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO specialization_tracks (player_id, track_type, xp_amount, level) VALUES (in_player_id, in_track_type, in_xp_amount, in_level)
|
|
ON CONFLICT(player_id, track_type) DO UPDATE SET xp_amount = in_xp_amount, level = in_level;
|
|
END $function$
|
|
|
|
|
|
-- setup_user_data_encryption(IN in_enable boolean) -> void
|
|
-- oid: 58597 kind: PROCEDURE category: encryption
|
|
|
|
CREATE OR REPLACE PROCEDURE dune.setup_user_data_encryption(IN in_enable boolean)
|
|
LANGUAGE plpgsql
|
|
AS $procedure$
|
|
declare
|
|
encryption_key Text;
|
|
encryption_key_hash bytea;
|
|
stored_encryption_key_hash bytea;
|
|
stored_encryption_status UserDataEncryptionStatus;
|
|
begin
|
|
select current_setting('funcom.user_data_encryption_key', true) into encryption_key;
|
|
-- might be null if the encryption_key is null
|
|
select ext.digest(encryption_key, 'md5') into encryption_key_hash;
|
|
-- might be null if the stored data is not encrypted
|
|
select get_stored_user_data_encryption_key_hash() into stored_encryption_key_hash;
|
|
|
|
-- should never be null
|
|
select get_stored_user_data_encryption_status() into stored_encryption_status;
|
|
|
|
drop index if exists encrypted_player_state_character_name_gin;
|
|
|
|
if stored_encryption_status = 'Disabled' then
|
|
if in_enable then
|
|
perform _user_data_encryption_setup_enabled(encryption_key_hash);
|
|
perform _user_data_encryption_initially_encrypt_existing_data();
|
|
else
|
|
-- technically we shouldn't do anything but let's just validate a few things
|
|
-- we not replacing get_stored_user_data_encryption_key_hash()
|
|
if (select get_stored_user_data_encryption_key_hash()) is not null then
|
|
-- should have been filtered by the main setup function
|
|
raise exception 'The data is encrypted, should use the taint version';
|
|
end if;
|
|
|
|
if (select get_stored_user_data_encryption_taint_xmax()) is not null then
|
|
-- should have been filtered by the main setup function
|
|
raise exception 'The data is tainted, should use the taint version';
|
|
end if;
|
|
end if;
|
|
elseif stored_encryption_status = 'Tainted' then
|
|
-- doesn't matter what we want, we get the tainted version
|
|
perform _user_data_encryption_setup_tainted();
|
|
else -- Enabled
|
|
if in_enable is null or in_enable then
|
|
if encryption_key_hash = stored_encryption_key_hash then -- and our key is the same
|
|
perform _user_data_encryption_setup_enabled(encryption_key_hash);
|
|
else
|
|
raise warning 'User-data encryption requested but the data is already encrypted with a different key';
|
|
perform _user_data_encryption_setup_tainted();
|
|
end if;
|
|
else
|
|
raise warning 'User-data encryption not requested but the data is already encrypted';
|
|
perform _user_data_encryption_setup_tainted();
|
|
end if;
|
|
end if;
|
|
|
|
commit;
|
|
|
|
CREATE INDEX encrypted_player_state_character_name_gin ON encrypted_player_state USING GIN((decrypt_user_data(encrypted_character_name)) ext.gin_trgm_ops);
|
|
end
|
|
$procedure$
|
|
|
|
|
|
-- store_backup_vehicle(in_vehicle_id bigint, in_account_id bigint, in_customization_id text) -> void
|
|
-- oid: 58598 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.store_backup_vehicle(in_vehicle_id bigint, in_account_id bigint, in_customization_id text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
-- Lock the backup_vehicles table exclusively to prevent race conditions.
|
|
LOCK TABLE backup_vehicles IN EXCLUSIVE MODE;
|
|
|
|
-- Check if the vehicle already belongs to an actor state
|
|
PERFORM 1 FROM actor_state WHERE actor_id = in_vehicle_id;
|
|
IF FOUND THEN
|
|
RAISE EXCEPTION 'Trying to backup vehicle % that already has an actor state.', in_vehicle_id;
|
|
END IF;
|
|
|
|
-- Check if the vehicle is already in backup_vehicles.
|
|
PERFORM 1 FROM backup_vehicles WHERE vehicle_id = in_vehicle_id;
|
|
IF FOUND THEN
|
|
RAISE EXCEPTION 'Vehicle % is already stored as a backup.', in_vehicle_id;
|
|
END IF;
|
|
|
|
-- Check if the vehicle exists in the actors table.
|
|
PERFORM 1 FROM actors WHERE id = in_vehicle_id;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Vehicle % does not exist in actors.', in_vehicle_id;
|
|
END IF;
|
|
|
|
-- Insert the vehicle into backup_vehicles.
|
|
INSERT INTO backup_vehicles (account_id, vehicle_id, customization_id)
|
|
VALUES (in_account_id, in_vehicle_id, in_customization_id);
|
|
RAISE INFO 'Inserted vehicle % into backup_vehicles for account %.', in_vehicle_id, in_account_id;
|
|
|
|
-- Mark the actor as belonging to the vehicle backup tool
|
|
INSERT INTO actor_state("actor_id", "state") VALUES(in_vehicle_id, 'VehicleBackup');
|
|
RAISE INFO 'Inserted vehicle % into actor_state with VehicleBackup state', in_vehicle_id;
|
|
|
|
PERFORM verify_item_dup_backup_tool(in_account_id, in_vehicle_id, 'item_dup_on_store_vbt');
|
|
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- store_recovered_vehicle(in_vehicle_id bigint, in_chassis_durability real, in_customization_id text, in_is_migration boolean) -> void
|
|
-- oid: 58599 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.store_recovered_vehicle(in_vehicle_id bigint, in_chassis_durability real, in_customization_id text, in_is_migration boolean DEFAULT false)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
owner_id BIGINT;
|
|
player_id BIGINT;
|
|
vehicle_class TEXT;
|
|
vehicle_name TEXT;
|
|
BEGIN
|
|
-- Lock the recovered_vehicles table exclusively to prevent race conditions.
|
|
LOCK TABLE recovered_vehicles IN EXCLUSIVE MODE;
|
|
|
|
-- Check if the vehicle already belongs to an actor state
|
|
PERFORM 1 FROM actor_state WHERE actor_id = in_vehicle_id;
|
|
IF FOUND THEN
|
|
RAISE EXCEPTION 'Trying to store recovered vehicle % that already has an actor state.', in_vehicle_id;
|
|
END IF;
|
|
|
|
-- Check if the vehicle is already in recovered_vehicles.
|
|
PERFORM 1 FROM recovered_vehicles WHERE vehicle_id = in_vehicle_id;
|
|
IF FOUND THEN
|
|
RAISE EXCEPTION 'Vehicle % is already recovered.', in_vehicle_id;
|
|
END IF;
|
|
|
|
-- Check if the vehicle exists in the actors table.
|
|
SELECT class INTO vehicle_class
|
|
FROM actors
|
|
WHERE id = in_vehicle_id
|
|
LIMIT 1;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Vehicle % does not exist in actors.', in_vehicle_id;
|
|
END IF;
|
|
|
|
-- get the vehicles owner account id
|
|
SELECT a.owner_account_id, r.player_id, p.actor_name INTO owner_id, player_id, vehicle_name
|
|
FROM actors a
|
|
INNER JOIN permission_actor_rank r ON r.player_id = a.id
|
|
INNER JOIN permission_actor p ON p.actor_id = r.permission_actor_id
|
|
WHERE r.permission_actor_id = in_vehicle_id
|
|
AND r.rank = 1::smallint
|
|
LIMIT 1;
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'No account_id found for vehicle: %', in_vehicle_id;
|
|
END IF;
|
|
|
|
-- Insert the vehicle into recovered_vehicles.
|
|
INSERT INTO recovered_vehicles(account_id, vehicle_id, chassis_durability, vehicle_name, customization_id, migrated)
|
|
VALUES (owner_id, in_vehicle_id, in_chassis_durability, vehicle_name, in_customization_id, in_is_migration);
|
|
RAISE INFO 'Inserted vehicle % into recovered_vehicles for account %.', in_vehicle_id, owner_id;
|
|
|
|
-- Mark the actor as belonging to the vehicle recovery tool
|
|
INSERT INTO actor_state("actor_id", "state") VALUES(in_vehicle_id, 'VehicleRecovery');
|
|
RAISE INFO 'Inserted vehicle % into actor_state with VehicleRecovery state', in_vehicle_id;
|
|
|
|
PERFORM pg_notify('vehicle_recovery_notify_channel', FORMAT('stored#{"PlayerId":%s, "VehicleId":%s, "VehicleClass":"%s", "VehicleName":"%s", "VehicleCustomizationId":"%s", "TimeStored":"%s", "ChassisDurability":%s, "bIsMigrated":%s}', player_id, in_vehicle_id, vehicle_class, vehicle_name, in_customization_id, NOW() AT TIME ZONE 'UTC', in_chassis_durability, CASE WHEN in_is_migration THEN 'true' ELSE 'false' END) );
|
|
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- store_recovered_vehicles_wiped_before_spawn(in_vehicle_ids bigint[], in_delete_items boolean) -> void
|
|
-- oid: 58600 kind: FUNCTION category: vehicle
|
|
|
|
CREATE OR REPLACE FUNCTION dune.store_recovered_vehicles_wiped_before_spawn(in_vehicle_ids bigint[], in_delete_items boolean DEFAULT true)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
to_store RECORD;
|
|
BEGIN
|
|
FOR to_store IN
|
|
SELECT v.id AS vehicle_id, a.properties -> (regexp_replace("class", '^.*\.', '')) ->> 'm_CustomizationId' AS customization_id
|
|
FROM actors a
|
|
INNER JOIN vehicles v ON a.id = v.id
|
|
INNER JOIN permission_actor p ON a.id = p.actor_id
|
|
INNER JOIN permission_actor_rank r ON p.actor_id = r.permission_actor_id
|
|
WHERE v.id = ANY(in_vehicle_ids)
|
|
AND r.rank = 1::smallint
|
|
AND NOT EXISTS
|
|
(
|
|
SELECT 1 FROM actor_state
|
|
WHERE actor_state.actor_id = v.id
|
|
AND actor_state.state IS DISTINCT FROM 'Default'
|
|
)
|
|
LOOP
|
|
-- remove all items in all inventories of that vehicle
|
|
if in_delete_items then
|
|
PERFORM delete_items_from_actor(to_store.vehicle_id);
|
|
end if;
|
|
|
|
-- note: storing hardcoded chassis durability because its not available from pure database :(
|
|
-- this will only be shown incorrectly in UI though, the spawned vehicle will get the correct value
|
|
PERFORM store_recovered_vehicle(to_store.vehicle_id, 0.25, to_store.customization_id);
|
|
|
|
-- remove permissions so the stored vehicles don't count towards the vehicle limit (the owner is preserved in the store function above)
|
|
PERFORM permission_actor_destroy(to_store.vehicle_id);
|
|
END LOOP;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- takeover_account(in_user_to_takeover text, in_current_user text) -> void
|
|
-- oid: 58601 kind: FUNCTION category: takeover
|
|
|
|
CREATE OR REPLACE FUNCTION dune.takeover_account(in_user_to_takeover text, in_current_user text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
current_funcom_id ByteA;
|
|
current_account_id BigInt;
|
|
|
|
takeover_funcom_id ByteA;
|
|
takeover_account_id BigInt;
|
|
BEGIN
|
|
select "encrypted_funcom_id", "id" into current_funcom_id, current_account_id
|
|
from encrypted_accounts WHERE "user"=in_current_user;
|
|
|
|
select "encrypted_funcom_id", "id" into takeover_funcom_id, takeover_account_id
|
|
from encrypted_accounts WHERE "user"=in_user_to_takeover;
|
|
|
|
-- Account swap
|
|
UPDATE encrypted_accounts SET "user"=in_current_user || 'TempTakeover' WHERE "id"=current_account_id;
|
|
UPDATE encrypted_accounts SET "user"=in_current_user, "encrypted_funcom_id"=current_funcom_id WHERE "id"=takeover_account_id;
|
|
UPDATE encrypted_accounts SET "user"=in_user_to_takeover, "encrypted_funcom_id"=takeover_funcom_id WHERE "id"=current_account_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- taxation_emit_invoices(new_tax_invoices dune.taxinvoicedata[]) -> void
|
|
-- oid: 58602 kind: FUNCTION category: taxation
|
|
|
|
CREATE OR REPLACE FUNCTION dune.taxation_emit_invoices(new_tax_invoices dune.taxinvoicedata[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
invoice_ids BIGINT[];
|
|
new_invoice_id BIGINT;
|
|
new_tax_invoice TaxInvoiceData;
|
|
BEGIN
|
|
IF array_length(new_tax_invoices, 1) > 0 THEN
|
|
FOREACH new_tax_invoice IN ARRAY new_tax_invoices LOOP
|
|
|
|
INSERT INTO tax_invoice("totem_id", "reference_timespan", "invoice_status", "amount")
|
|
VALUES(new_tax_invoice.totem_id, new_tax_invoice.reference_timespan, new_tax_invoice.invoice_status, new_tax_invoice.amount) RETURNING id INTO new_invoice_id;
|
|
|
|
invoice_ids := array_append(invoice_ids, new_invoice_id);
|
|
END LOOP;
|
|
|
|
PERFORM pg_notify('taxation_notify_channel', format('emit_invoices|{"InvoiceIds" : %s, "InvoiceData" : %s}', to_json(invoice_ids)::text, to_json(new_tax_invoices)::text));
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- taxation_get_all_invoices_for_player(in_player_id bigint) -> TABLE(id bigint, totem_id bigint, reference_timestamp bigint, invoice_status smallint, amount integer, actor_name text)
|
|
-- oid: 58603 kind: FUNCTION category: taxation
|
|
|
|
CREATE OR REPLACE FUNCTION dune.taxation_get_all_invoices_for_player(in_player_id bigint)
|
|
RETURNS TABLE(id bigint, totem_id bigint, reference_timestamp bigint, invoice_status smallint, amount integer, actor_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT tax_invoice.id, tax_invoice.totem_id, tax_invoice.reference_timespan, tax_invoice.invoice_status, tax_invoice.amount, permission_actor.actor_name
|
|
FROM tax_invoice
|
|
JOIN permission_actor ON permission_actor.actor_id = tax_invoice.totem_id
|
|
JOIN permission_actor_rank ON permission_actor.actor_id = permission_actor_rank.permission_actor_id
|
|
WHERE permission_actor_rank.player_id = in_player_id
|
|
ORDER BY tax_invoice.reference_timespan;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- taxation_get_all_invoices_for_server(map_name text, in_dimension_index integer, in_partition_id bigint) -> TABLE(id bigint, totem_id bigint, reference_timestamp bigint, invoice_status smallint, amount integer, actor_name text)
|
|
-- oid: 58604 kind: FUNCTION category: taxation
|
|
|
|
CREATE OR REPLACE FUNCTION dune.taxation_get_all_invoices_for_server(map_name text, in_dimension_index integer, in_partition_id bigint)
|
|
RETURNS TABLE(id bigint, totem_id bigint, reference_timestamp bigint, invoice_status smallint, amount integer, actor_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT tax_invoice.id, actors.id, tax_invoice.reference_timespan, tax_invoice.invoice_status, tax_invoice.amount, permission_actor.actor_name
|
|
FROM tax_invoice
|
|
JOIN permission_actor ON permission_actor.actor_id = tax_invoice.totem_id
|
|
JOIN actors ON actors.id = tax_invoice.totem_id
|
|
WHERE actors.map = map_name
|
|
AND actors.dimension_index = in_dimension_index
|
|
AND ((in_partition_id = 0 AND actors.partition_id IS NULL) OR actors.partition_id = in_partition_id)
|
|
ORDER BY tax_invoice.reference_timespan;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- taxation_get_all_invoices_for_totem(in_totem_id bigint) -> TABLE(id bigint, totem_id bigint, reference_timestamp bigint, invoice_status smallint, amount integer, actor_name text)
|
|
-- oid: 58605 kind: FUNCTION category: taxation
|
|
|
|
CREATE OR REPLACE FUNCTION dune.taxation_get_all_invoices_for_totem(in_totem_id bigint)
|
|
RETURNS TABLE(id bigint, totem_id bigint, reference_timestamp bigint, invoice_status smallint, amount integer, actor_name text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN QUERY SELECT tax_invoice.id, actors.id, tax_invoice.reference_timespan, tax_invoice.invoice_status, tax_invoice.amount, permission_actor.actor_name
|
|
FROM tax_invoice
|
|
JOIN permission_actor ON permission_actor.actor_id = tax_invoice.totem_id
|
|
JOIN actors ON actors.id = tax_invoice.totem_id
|
|
WHERE actors.id = in_totem_id
|
|
ORDER BY tax_invoice.reference_timespan;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- taxation_pay_invoice(invoice_id bigint, paid_invoice_status smallint) -> bigint
|
|
-- oid: 58606 kind: FUNCTION category: taxation
|
|
|
|
CREATE OR REPLACE FUNCTION dune.taxation_pay_invoice(invoice_id bigint, paid_invoice_status smallint)
|
|
RETURNS bigint
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
found_invoice_id BIGINT;
|
|
BEGIN
|
|
UPDATE tax_invoice SET invoice_status = paid_invoice_status WHERE tax_invoice.id = invoice_id AND tax_invoice.invoice_status != paid_invoice_status RETURNING id INTO found_invoice_id;
|
|
if found_invoice_id IS NOT NULL THEN
|
|
PERFORM pg_notify('taxation_notify_channel', format('pay_invoice|{"InvoiceId" : %s }', invoice_id));
|
|
END IF;
|
|
RETURN found_invoice_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- taxation_remove_invoices(invoices_to_remove bigint[]) -> void
|
|
-- oid: 58607 kind: FUNCTION category: taxation
|
|
|
|
CREATE OR REPLACE FUNCTION dune.taxation_remove_invoices(invoices_to_remove bigint[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM tax_invoice WHERE id = ANY(invoices_to_remove);
|
|
PERFORM pg_notify('taxation_notify_channel', format('remove_invoice|{"InvoiceIds" : %s}', to_json(invoices_to_remove)::text));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- taxation_remove_invoices_from_totem(totem_actor_id bigint) -> void
|
|
-- oid: 58608 kind: FUNCTION category: taxation
|
|
|
|
CREATE OR REPLACE FUNCTION dune.taxation_remove_invoices_from_totem(totem_actor_id bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
invoice_ids BIGINT[];
|
|
BEGIN
|
|
SELECT array_agg(id) from tax_invoice into invoice_ids WHERE totem_id = totem_actor_id;
|
|
|
|
DELETE FROM tax_invoice WHERE totem_id = totem_actor_id;
|
|
PERFORM pg_notify('taxation_notify_channel', format('remove_invoice|{"InvoiceIds" : %s}', to_json(invoice_ids)::text));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- taxation_update_invoice_status(invoices_to_overdue bigint[], invoices_to_defaulted bigint[], overdue_invoice_status smallint, defaulted_invoice_status smallint) -> void
|
|
-- oid: 58609 kind: FUNCTION category: taxation
|
|
|
|
CREATE OR REPLACE FUNCTION dune.taxation_update_invoice_status(invoices_to_overdue bigint[], invoices_to_defaulted bigint[], overdue_invoice_status smallint, defaulted_invoice_status smallint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF array_length(invoices_to_overdue, 1) > 0 THEN
|
|
UPDATE tax_invoice SET invoice_status = overdue_invoice_status WHERE id = ANY(invoices_to_overdue);
|
|
PERFORM pg_notify('taxation_notify_channel', format('update_invoice_status|{"InvoiceStatus" : %s, "InvoiceIds" : %s}', overdue_invoice_status, to_json(invoices_to_overdue)::text));
|
|
END IF;
|
|
|
|
IF array_length(invoices_to_defaulted, 1) > 0 THEN
|
|
UPDATE tax_invoice SET invoice_status = defaulted_invoice_status WHERE id = ANY(invoices_to_defaulted);
|
|
PERFORM pg_notify('taxation_notify_channel', format('update_invoice_status|{"InvoiceStatus" : %s, "InvoiceIds" : %s}', defaulted_invoice_status, to_json(invoices_to_defaulted)::text));
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- try_prime_spicefield(in_source_server_id text, in_spicefield_id integer) -> boolean
|
|
-- oid: 58610 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.try_prime_spicefield(in_source_server_id text, in_spicefield_id integer)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
perform spicefield_type_id from spicefield_types as t
|
|
where t.spicefield_type_id = in_spicefield_id and t.is_spawning_active is true and t.current_globally_primed < t.max_globally_primed and t.current_globally_active < t.max_globally_active;
|
|
if not found then
|
|
return false;
|
|
end if;
|
|
|
|
update spicefield_server_availability
|
|
set inactive_fields_of_type = inactive_fields_of_type - 1
|
|
where server_id = in_source_server_id and spicefield_type_id = in_spicefield_id;
|
|
|
|
update spicefield_types
|
|
set current_globally_primed = current_globally_primed + 1
|
|
where spicefield_type_id = in_spicefield_id;
|
|
|
|
return true;
|
|
commit;
|
|
end $function$
|
|
|
|
|
|
-- try_restart_spicefield(in_server_id text, in_spicefield_type_id integer) -> boolean
|
|
-- oid: 58611 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.try_restart_spicefield(in_server_id text, in_spicefield_type_id integer)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM spicefield_type_id
|
|
FROM spicefield_types AS t
|
|
WHERE t.spicefield_type_id = in_spicefield_type_id AND t.is_spawning_active IS TRUE;
|
|
IF NOT FOUND THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
UPDATE spicefield_server_availability
|
|
SET inactive_fields_of_type = inactive_fields_of_type - 1
|
|
WHERE server_id = in_server_id AND spicefield_type_id = in_spicefield_type_id;
|
|
|
|
UPDATE spicefield_types
|
|
SET current_globally_active = current_globally_active + 1
|
|
WHERE spicefield_type_id = in_spicefield_type_id;
|
|
|
|
RETURN TRUE;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- try_spawn_spicefield(in_source_server_id text, in_spicefield_id integer) -> boolean
|
|
-- oid: 58612 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.try_spawn_spicefield(in_source_server_id text, in_spicefield_id integer)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
perform spicefield_type_id from spicefield_types as t
|
|
where t.spicefield_type_id = in_spicefield_id and t.is_spawning_active is true and t.current_globally_active < t.max_globally_active;
|
|
if not found then
|
|
return false;
|
|
end if;
|
|
|
|
update spicefield_server_availability
|
|
set requested_spawned_of_type = requested_spawned_of_type - 1
|
|
where server_id = in_source_server_id and spicefield_type_id = in_spicefield_id;
|
|
|
|
update spicefield_types
|
|
set current_globally_active = current_globally_active + 1, current_globally_primed = current_globally_primed -1
|
|
where spicefield_type_id = in_spicefield_id;
|
|
|
|
return true;
|
|
commit;
|
|
end $function$
|
|
|
|
|
|
-- try_update_exchange_categories_hash(in_new_hash integer) -> TABLE(item_template_id text, mask integer, depth smallint)
|
|
-- oid: 58613 kind: FUNCTION category: exchange
|
|
|
|
CREATE OR REPLACE FUNCTION dune.try_update_exchange_categories_hash(in_new_hash integer)
|
|
RETURNS TABLE(item_template_id text, mask integer, depth smallint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT * FROM dune_exchange_categories_hash) FOR UPDATE THEN
|
|
INSERT INTO dune_exchange_categories_hash(id, hash) VALUES(1, in_new_hash);
|
|
RETURN;
|
|
END IF;
|
|
IF NOT in_new_hash IN (SELECT hash FROM dune_exchange_categories_hash FOR SHARE) THEN
|
|
UPDATE dune_exchange_categories_hash SET hash = in_new_hash WHERE dune_exchange_categories_hash.id = 1;
|
|
RETURN QUERY SELECT DISTINCT template_id, category_mask, category_depth FROM dune_exchange_orders;
|
|
END IF;
|
|
RETURN;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- unassign_partition(in_server_id text) -> boolean
|
|
-- oid: 58614 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.unassign_partition(in_server_id text)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
v_affected_rows BigInt;
|
|
BEGIN
|
|
UPDATE world_partition SET server_id = null WHERE server_id = in_server_id;
|
|
get diagnostics v_affected_rows = ROW_COUNT;
|
|
|
|
-- If we didn't actually unassign anything, we have no need to trigger the notification (as nothing changed)
|
|
if v_affected_rows > 0 then
|
|
NOTIFY world_partition_update;
|
|
return true;
|
|
end if;
|
|
return false;
|
|
END $function$
|
|
|
|
|
|
-- update_communinet_player_channel(in_account_id bigint, in_channel_name text, in_is_tuned boolean) -> void
|
|
-- oid: 58615 kind: FUNCTION category: communinet
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_communinet_player_channel(in_account_id bigint, in_channel_name text, in_is_tuned boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO communinet_player_channels(account_id, channel_name, is_tuned) VALUES (in_account_id, in_channel_name, in_is_tuned)
|
|
ON CONFLICT(account_id, channel_name) DO UPDATE SET is_tuned = in_is_tuned WHERE communinet_player_channels.account_id = in_account_id AND communinet_player_channels.channel_name = in_channel_name;
|
|
END $function$
|
|
|
|
|
|
-- update_communinet_player_data(in_account_id bigint, in_is_active boolean, in_selected_channel_name text) -> void
|
|
-- oid: 58616 kind: FUNCTION category: communinet
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_communinet_player_data(in_account_id bigint, in_is_active boolean, in_selected_channel_name text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO communinet_player(account_id, is_active, selected_channel_name) VALUES (in_account_id, in_is_active, in_selected_channel_name)
|
|
ON CONFLICT(account_id) DO UPDATE SET is_active = in_is_active, selected_channel_name = in_selected_channel_name WHERE communinet_player.account_id = in_account_id;
|
|
END $function$
|
|
|
|
|
|
-- update_consumed_per_player_lore(in_actor_id bigint, in_consumed_bit_array bit, in_use_temporary boolean) -> void
|
|
-- oid: 58617 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_consumed_per_player_lore(in_actor_id bigint, in_consumed_bit_array bit, in_use_temporary boolean)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF in_use_temporary THEN
|
|
INSERT INTO consumed_temporary_per_player_lore(actor_id, consumed_bit_array)
|
|
VALUES(in_actor_id, in_consumed_bit_array)
|
|
ON CONFLICT (actor_id)
|
|
DO UPDATE SET
|
|
consumed_bit_array = in_consumed_bit_array;
|
|
ELSE
|
|
INSERT INTO consumed_per_player_lore(actor_id, consumed_bit_array)
|
|
VALUES(in_actor_id, in_consumed_bit_array)
|
|
ON CONFLICT (actor_id)
|
|
DO UPDATE SET
|
|
consumed_bit_array = in_consumed_bit_array;
|
|
END IF;
|
|
END; $function$
|
|
|
|
|
|
-- update_coriolis_for_player(in_controller_id bigint, OUT out_was_coriolis_processed boolean) -> boolean
|
|
-- oid: 58618 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_coriolis_for_player(in_controller_id bigint, OUT out_was_coriolis_processed boolean)
|
|
RETURNS boolean
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
SELECT is_coriolis_processed INTO out_was_coriolis_processed
|
|
FROM player_state WHERE player_controller_id = in_controller_id;
|
|
UPDATE player_state SET is_coriolis_processed = TRUE WHERE player_controller_id = in_controller_id;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- update_death_location(in_pawn dune.actordescription, in_server_info dune.serverinfo, in_life_state dune.playerlifestate) -> void
|
|
-- oid: 58619 kind: FUNCTION category: player_persistence
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_death_location(in_pawn dune.actordescription, in_server_info dune.serverinfo, in_life_state dune.playerlifestate)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF in_life_state IS NOT NULL THEN
|
|
UPDATE encrypted_player_state
|
|
SET
|
|
life_state = in_life_state,
|
|
death_location = CASE
|
|
WHEN in_life_state != 'Alive'::PlayerLifeState THEN ((in_pawn).transform.location, (in_server_info).map, (in_server_info).dimension_index)::DeathLocation
|
|
ELSE null
|
|
END
|
|
WHERE player_pawn_id = in_pawn.id;
|
|
END IF;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- update_farm_state(in_server_id text, in_outgoing_s2s_connections integer, in_incoming_s2s_connections integer, in_connected_players integer, in_farm_id text, in_igw_addr inet, in_igw_port integer, in_ready boolean, in_alive boolean, in_game_addr inet, in_game_port integer, in_map text, in_revision integer) -> void
|
|
-- oid: 58620 kind: FUNCTION category: farm
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_farm_state(in_server_id text, in_outgoing_s2s_connections integer, in_incoming_s2s_connections integer, in_connected_players integer, in_farm_id text, in_igw_addr inet, in_igw_port integer, in_ready boolean, in_alive boolean, in_game_addr inet, in_game_port integer, in_map text, in_revision integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO farm_state
|
|
(server_id, outgoing_s2s_connections, incoming_s2s_connections, connected_players, farm_id, igw_addr, igw_port, ready, alive, game_addr, game_port, map, revision)
|
|
VALUES
|
|
(in_server_id, in_outgoing_s2s_connections, in_incoming_s2s_connections, in_connected_players, in_farm_id, in_igw_addr, in_igw_port, in_ready, in_alive, in_game_addr, in_game_port, in_map, in_revision)
|
|
ON CONFLICT(server_id) DO UPDATE SET
|
|
outgoing_s2s_connections=in_outgoing_s2s_connections, incoming_s2s_connections=in_incoming_s2s_connections, connected_players=in_connected_players, farm_id=in_farm_id, igw_addr=in_igw_addr, igw_port=in_igw_port, ready=in_ready, alive=in_alive, game_addr=in_game_addr, game_port=in_game_port, map=in_map, revision=in_revision
|
|
WHERE
|
|
farm_state.server_id = in_server_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- update_global_spice_field_rules(in_max_globally_primed integer, in_max_globally_active integer, in_spicefield_type_id integer) -> void
|
|
-- oid: 58621 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_global_spice_field_rules(in_max_globally_primed integer, in_max_globally_active integer, in_spicefield_type_id integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE spicefield_types SET max_globally_primed = in_max_globally_primed, max_globally_active = in_max_globally_active WHERE spicefield_type_id = in_spicefield_type_id;
|
|
END; $function$
|
|
|
|
|
|
-- update_inventories_data(in_inventory_data_list dune.inventorydata[]) -> void
|
|
-- oid: 58622 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_inventories_data(in_inventory_data_list dune.inventorydata[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE inventories
|
|
SET inventory_type = (u).inventory_type, max_item_count = (u).max_item_count, max_item_volume = (u).max_item_volume
|
|
FROM (SELECT inventory_id, inventory_type, max_item_count, max_item_volume FROM UNNEST(in_inventory_data_list)) u
|
|
WHERE id = (u).inventory_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- update_inventory(in_delete_list bigint[], in_stack_update dune.itemstackupdate[], in_quality_update dune.itemqualityupdate[], in_stat_update dune.itemstatupdate[], in_item_locations dune.inventoryitemlocation[]) -> void
|
|
-- oid: 58623 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_inventory(in_delete_list bigint[], in_stack_update dune.itemstackupdate[], in_quality_update dune.itemqualityupdate[], in_stat_update dune.itemstatupdate[], in_item_locations dune.inventoryitemlocation[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
delete_item_id BIGINT;
|
|
BEGIN
|
|
-- log item movement
|
|
PERFORM _add_item_trace_log('update_inventory_locations', in_item_locations);
|
|
|
|
-- delete items
|
|
PERFORM delete_items(in_delete_list);
|
|
|
|
-- update item stacks
|
|
UPDATE items SET "stack_size" = (u).stack_size FROM (SELECT stack_size, item_id FROM UNNEST(in_stack_update)) u WHERE "id" = (u).item_id;
|
|
|
|
-- update item quality
|
|
UPDATE items SET "quality_level" = (u).quality_level FROM (SELECT quality_level, item_id FROM UNNEST(in_quality_update)) u WHERE "id" = (u).item_id;
|
|
|
|
-- update stats
|
|
UPDATE items SET "stats" = "stats" || (u).value FROM (SELECT value, item_id FROM UNNEST(in_stat_update)) u WHERE "id" = (u).item_id;
|
|
|
|
UPDATE items
|
|
SET inventory_id = (item).inventory_id, position_index = (item).position_index
|
|
FROM (SELECT item_id, inventory_id, position_index FROM UNNEST(in_item_locations)) item
|
|
WHERE id = (item).item_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- update_item_locations(in_item_locations dune.inventoryitemlocation[]) -> void
|
|
-- oid: 58624 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_item_locations(in_item_locations dune.inventoryitemlocation[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE items
|
|
SET inventory_id = (item).inventory_id, position_index = (item).position_index
|
|
FROM (SELECT item_id, inventory_id, position_index FROM UNNEST(in_item_locations)) item
|
|
WHERE id = (item).item_id;
|
|
|
|
-- log item tracking
|
|
PERFORM _add_item_trace_log('update_item_locations', in_item_locations);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- update_journey_story_ids(old_story_ids text[], new_story_ids text[]) -> void
|
|
-- oid: 58625 kind: FUNCTION category: journey_progression
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_journey_story_ids(old_story_ids text[], new_story_ids text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
index INT;
|
|
BEGIN
|
|
IF array_length(old_story_ids, 1) != array_length(new_story_ids, 1) THEN
|
|
RAISE EXCEPTION 'The length of the array of old IDs does not match the length of the array of new IDs - they must both have the same length';
|
|
END IF;
|
|
|
|
FOR index in 1 .. array_length(old_story_ids, 1) LOOP
|
|
UPDATE journey_story_node
|
|
SET story_node_id = new_story_ids[index]
|
|
WHERE story_node_id = old_story_ids[index];
|
|
|
|
UPDATE journey_story_node_cooldown
|
|
SET story_node_id = new_story_ids[index]
|
|
WHERE story_node_id = old_story_ids[index];
|
|
END LOOP;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- update_marker_ids(in_old_ids integer[], in_new_ids integer[]) -> void
|
|
-- oid: 58626 kind: FUNCTION category: markers
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_marker_ids(in_old_ids integer[], in_new_ids integer[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE markers SET marker_hash_id = data_table.new_id, marker.z = 0 from (select unnest(in_old_ids) as old_id, unnest(in_new_ids) as new_id) as data_table WHERE markers.marker_hash_id = data_table.old_id;
|
|
END; $function$
|
|
|
|
|
|
-- update_partition_labels(in_allow_overwrite boolean) -> void
|
|
-- oid: 58627 kind: FUNCTION category: partition
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_partition_labels(in_allow_overwrite boolean DEFAULT true)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
-- Compute candidate labels per-partition using the helper and apply them where appropriate
|
|
UPDATE world_partition wp
|
|
SET label = sub.new_label
|
|
FROM (
|
|
SELECT partition_id, determine_partition_label(map, dimension_index, label, in_allow_overwrite, partition_id) AS new_label
|
|
FROM world_partition
|
|
) AS sub
|
|
WHERE wp.partition_id = sub.partition_id
|
|
AND (wp.label IS NULL OR in_allow_overwrite = true)
|
|
AND sub.new_label IS NOT NULL;
|
|
|
|
-- The default is `MAP_DIMENSION`
|
|
-- Only set it for map, dimension combos that have a single partition (label must be unique), and for labels not already touched
|
|
UPDATE world_partition SET label = map || '_' || dimension_index
|
|
from (
|
|
select grouping.partition_ids[1] as partition_id
|
|
from (
|
|
select count(*) as count, array_agg(partition_id) as partition_ids
|
|
from world_partition
|
|
group by map, dimension_index
|
|
) as grouping
|
|
where grouping.count = 1
|
|
) as partition
|
|
where
|
|
world_partition.partition_id = partition.partition_id
|
|
and label is null;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- update_party_platform_session(in_party_id bigint, in_platform_session_id text, in_platform_name text) -> void
|
|
-- oid: 58628 kind: FUNCTION category: party
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_party_platform_session(in_party_id bigint, in_platform_session_id text, in_platform_name text)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF in_platform_session_id IS NULL OR length(in_platform_session_id) = 0 THEN
|
|
RAISE EXCEPTION 'in_platform_session_id must not be empty';
|
|
END IF;
|
|
|
|
IF in_platform_name IS NULL OR length(in_platform_name) = 0 THEN
|
|
RAISE EXCEPTION 'platform_name must not be empty';
|
|
END IF;
|
|
|
|
INSERT INTO platform_parties_mapping (platform_session_id, platform_name, dune_party_id)
|
|
VALUES (in_platform_session_id, in_platform_name, in_party_id)
|
|
ON CONFLICT (platform_name, dune_party_id)
|
|
DO UPDATE SET platform_session_id = EXCLUDED.platform_session_id;
|
|
|
|
PERFORM pg_notify('party_notify_channel', format('update_party_platform_id#{"PartyId" : %s, "PlatformSessionId" : "%s", "PlatformName" : "%s"}',
|
|
in_party_id, in_platform_session_id, in_platform_name));
|
|
END
|
|
$function$
|
|
|
|
|
|
-- update_player_tags(in_account_id bigint, tags_to_add text[], tags_to_remove text[]) -> void
|
|
-- oid: 58629 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_player_tags(in_account_id bigint, tags_to_add text[], tags_to_remove text[])
|
|
RETURNS void
|
|
LANGUAGE sql
|
|
AS $function$
|
|
insert into player_tags("account_id", "tag") select in_account_id, unnest(tags_to_add) on conflict do nothing;
|
|
delete from player_tags where account_id = in_account_id and tag = ANY(tags_to_remove);
|
|
$function$
|
|
|
|
|
|
-- update_removed_items_and_recipes(items_removed text[], recipes_removed text[]) -> void
|
|
-- oid: 58630 kind: FUNCTION category: items_purge
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_removed_items_and_recipes(items_removed text[], recipes_removed text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
insert into removed_items (name) select unnest(items_removed);
|
|
insert into removed_recipes (name) select unnest(recipes_removed);
|
|
end;
|
|
$function$
|
|
|
|
|
|
-- update_resourcefield_states(in_map text, in_dimension_index integer, in_field_kind_id smallint, in_field_states dune.resourcefieldstateentry[]) -> void
|
|
-- oid: 58631 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_resourcefield_states(in_map text, in_dimension_index integer, in_field_kind_id smallint, in_field_states dune.resourcefieldstateentry[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO resourcefield_state(map, dimension_index, field_kind_id, field_id, spawn_time, value_remaining)
|
|
SELECT in_map, in_dimension_index, in_field_kind_id, * FROM UNNEST(in_field_states)
|
|
ON CONFLICT("field_id", "map", "dimension_index") DO
|
|
UPDATE
|
|
SET value_remaining = EXCLUDED.value_remaining
|
|
WHERE resourcefield_state.field_id = EXCLUDED.field_id AND resourcefield_state.map = in_map AND resourcefield_state.dimension_index = in_dimension_index;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- update_respawn_locations(player_id bigint, respawn_locations dune.respawnlocation[]) -> void
|
|
-- oid: 58632 kind: FUNCTION category: spawner
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_respawn_locations(player_id bigint, respawn_locations dune.respawnlocation[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
PERFORM 1
|
|
FROM unnest(respawn_locations) AS loc
|
|
WHERE
|
|
(loc.locator).type != 'Invalid' AND NOT (
|
|
(loc.locator).type = 'Transform' AND (loc.locator).transform IS NOT NULL AND (loc.locator).actor_id IS NULL AND (loc.locator).name IS NULL
|
|
OR
|
|
(loc.locator).type = 'PersistentActor' AND (loc.locator).actor_id IS NOT NULL AND (loc.locator).transform IS NULL AND (loc.locator).name IS NULL
|
|
OR
|
|
(loc.locator).type = 'StaticLocatorName' AND (loc.locator).name IS NOT NULL AND (loc.locator).transform IS NULL AND (loc.locator).actor_id IS NULL
|
|
);
|
|
|
|
IF FOUND THEN
|
|
RAISE EXCEPTION 'Invalid respawn location in input array. Check locator type and associated fields.';
|
|
END IF;
|
|
|
|
WITH
|
|
updated_respawn_locations AS (
|
|
SELECT
|
|
id,
|
|
"group",
|
|
(locator).transform AS locator_transform,
|
|
(locator).actor_id AS locator_actor_id,
|
|
(locator).name AS locator_name,
|
|
(locator).name_index AS locator_name_index,
|
|
map,
|
|
dimension,
|
|
last_used_timestamp
|
|
FROM unnest(respawn_locations) AS updated
|
|
),
|
|
delete_missing_respawn_locations AS (
|
|
DELETE FROM player_respawn_locations AS existing
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM updated_respawn_locations AS updated WHERE updated.id = existing.id
|
|
)
|
|
AND existing.account_id = player_id
|
|
)
|
|
INSERT INTO player_respawn_locations(
|
|
"id", "account_id", "group", "locator_transform", "locator_actor_id", "locator_name", "locator_name_index", "map", "dimension", "last_used_timestamp"
|
|
)
|
|
SELECT
|
|
up.id, player_id, up.group, up.locator_transform, up.locator_actor_id, up.locator_name, up.locator_name_index, up.map, up.dimension, up.last_used_timestamp
|
|
FROM updated_respawn_locations AS up
|
|
WHERE up.locator_actor_id IS NULL OR EXISTS (
|
|
SELECT 1 FROM actors WHERE id = up.locator_actor_id
|
|
)
|
|
ON CONFLICT ("id", "account_id")
|
|
DO UPDATE SET
|
|
"account_id" = EXCLUDED.account_id,
|
|
"group" = EXCLUDED.group,
|
|
"locator_transform" = EXCLUDED.locator_transform,
|
|
"locator_actor_id" = EXCLUDED.locator_actor_id,
|
|
"locator_name" = EXCLUDED.locator_name,
|
|
"locator_name_index" = EXCLUDED.locator_name_index,
|
|
"map" = EXCLUDED.map,
|
|
"dimension" = EXCLUDED.dimension,
|
|
"last_used_timestamp" = EXCLUDED.last_used_timestamp;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- update_returning_player_status(in_user_id text, in_minimum_returning_player_time_seconds integer) -> void
|
|
-- oid: 58633 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_returning_player_status(in_user_id text, in_minimum_returning_player_time_seconds integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
user_account_id BigInt;
|
|
last_login_time TIMESTAMPTZ;
|
|
last_award_time TIMESTAMPTZ;
|
|
BEGIN
|
|
SELECT INTO user_account_id, last_login_time, last_award_time id, ps.last_login_time, ps.last_returning_player_awarded_time
|
|
FROM accounts acc
|
|
JOIN player_state ps ON ps.account_id = acc.id
|
|
WHERE acc.user=in_user_id;
|
|
|
|
IF user_account_id IS NOT NULL THEN
|
|
IF last_award_time + INTERVAL '1 second' * in_minimum_returning_player_time_seconds > CURRENT_TIMESTAMP THEN
|
|
UPDATE player_state SET last_returning_player_event_time=NULL WHERE account_id=user_account_id;
|
|
ELSIF last_login_time + INTERVAL '1 second' * in_minimum_returning_player_time_seconds < CURRENT_TIMESTAMP THEN
|
|
UPDATE player_state SET last_returning_player_event_time=now() WHERE account_id=user_account_id;
|
|
END IF;
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- update_sell_orders_categories(category_update_data dune.exchangecategoryupdatedata[]) -> void
|
|
-- oid: 58634 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_sell_orders_categories(category_update_data dune.exchangecategoryupdatedata[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
UPDATE dune_exchange_orders SET category_mask = update_data.mask, category_depth = update_data.depth
|
|
FROM UNNEST(category_update_data) update_data
|
|
WHERE update_data.item_template_id = dune_exchange_orders.template_id;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- update_server_building_favorites(in_account_id bigint, in_building_types text[]) -> void
|
|
-- oid: 58635 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_server_building_favorites(in_account_id bigint, in_building_types text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO building_favorites(account_id, building_types)
|
|
VALUES(in_account_id, in_building_types)
|
|
ON CONFLICT(account_id) DO UPDATE SET building_types = in_building_types WHERE building_favorites.account_id = in_account_id;
|
|
END; $function$
|
|
|
|
|
|
-- update_server_learned_building_sets(in_account_id bigint, in_learned_building_sets text[]) -> void
|
|
-- oid: 58636 kind: FUNCTION category: building_blueprint
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_server_learned_building_sets(in_account_id bigint, in_learned_building_sets text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO building_progression(account_id, learned_building_sets)
|
|
VALUES(in_account_id, in_learned_building_sets)
|
|
ON CONFLICT(account_id) DO UPDATE SET learned_building_sets = in_learned_building_sets WHERE building_progression.account_id = in_account_id;
|
|
END; $function$
|
|
|
|
|
|
-- update_server_learned_new_buildable_pieces(in_account_id bigint, in_new_buildable_pieces text[]) -> void
|
|
-- oid: 58637 kind: FUNCTION category: server
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_server_learned_new_buildable_pieces(in_account_id bigint, in_new_buildable_pieces text[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
INSERT INTO building_progression(account_id, new_buildable_pieces)
|
|
VALUES(in_account_id, in_new_buildable_pieces)
|
|
ON CONFLICT(account_id) DO UPDATE SET new_buildable_pieces = in_new_buildable_pieces WHERE building_progression.account_id = in_account_id;
|
|
END; $function$
|
|
|
|
|
|
-- update_specialization_refund_id(in_player_id bigint, in_refund_id smallint, in_removed_keystones smallint[]) -> void
|
|
-- oid: 58638 kind: FUNCTION category: character_mod
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_specialization_refund_id(in_player_id bigint, in_refund_id smallint, in_removed_keystones smallint[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM purchased_specialization_keystones WHERE player_id = in_player_id AND keystone_id = ANY(in_removed_keystones);
|
|
|
|
INSERT INTO specialization_refund_id (player_id, refund_id) VALUES(in_player_id, in_refund_id)
|
|
ON conflict (player_id) DO UPDATE SET refund_id = in_refund_id;
|
|
END $function$
|
|
|
|
|
|
-- update_spice_field_spawn_state(in_is_spawning_active boolean, in_spicefield_type_id integer) -> void
|
|
-- oid: 58639 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_spice_field_spawn_state(in_is_spawning_active boolean, in_spicefield_type_id integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
UPDATE spicefield_types SET is_spawning_active = in_is_spawning_active WHERE spicefield_type_id = in_spicefield_type_id;
|
|
UPDATE spicefield_server_availability SET requested_spawned_of_type = 0 WHERE spicefield_type_id = in_spicefield_type_id;
|
|
END; $function$
|
|
|
|
|
|
-- update_traveling_actor_dependencies(in_dep dune.traveldependency[]) -> void
|
|
-- oid: 58640 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_traveling_actor_dependencies(in_dep dune.traveldependency[])
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
with valid_ids as (
|
|
with d as (select * from unnest(in_dep))
|
|
select d.id from d where d.id is not null
|
|
union
|
|
select d.parent_id from d where d.parent_id is not null
|
|
),
|
|
valid_ids_plus_dep as (
|
|
select * from valid_ids
|
|
union
|
|
select tap.id from travel_actor_parent as tap where tap.parent_id in (select * from valid_ids)
|
|
),
|
|
-- remove valid ids and connected dependencies from actor_state
|
|
delete_actor_state_ids AS (
|
|
delete from actor_state as acs
|
|
where acs.actor_id in (select * from valid_ids_plus_dep) and acs.state = 'Travel'
|
|
)
|
|
-- remove valid ids and connected dependencies from any other dependency tree
|
|
delete from travel_actor_parent
|
|
where id in (select * from valid_ids_plus_dep);
|
|
|
|
-- add/update dependencies with valid parent and child ids
|
|
with valid_dep as (
|
|
select a1.id as id, a2.id as parent_id, d.is_instigator
|
|
from unnest(in_dep) d
|
|
left join actors as a1
|
|
on d.id = a1.id
|
|
left join actors as a2
|
|
on d.parent_id = a2.id
|
|
where
|
|
a1.id is not null
|
|
and a2.id is not null
|
|
)
|
|
insert into travel_actor_parent (id, parent_id, is_instigator)
|
|
select * from valid_dep
|
|
on conflict (id) do update set
|
|
"parent_id" = excluded.parent_id,
|
|
"is_instigator" = excluded.is_instigator;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- update_traveling_actor_tree(in_actor_id bigint, in_target_transform dune.transform, in_target_map text, in_target_dimension_index integer, in_target_partition_id bigint) -> TABLE(out_id bigint, out_actor_state text)
|
|
-- oid: 58641 kind: FUNCTION category: actors
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_traveling_actor_tree(in_actor_id bigint, in_target_transform dune.transform, in_target_map text, in_target_dimension_index integer, in_target_partition_id bigint)
|
|
RETURNS TABLE(out_id bigint, out_actor_state text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
RETURN query WITH
|
|
traveling_actor_ids AS (
|
|
SELECT t.id FROM get_traveling_actor_ids(in_actor_id) AS t
|
|
),
|
|
invalid_traveling_actor_ids AS (
|
|
SELECT id, actor_state.state::TEXT FROM traveling_actor_ids
|
|
INNER JOIN actor_state ON actor_state.actor_id = traveling_actor_ids.id
|
|
WHERE actor_state.state != 'Travel'
|
|
),
|
|
valid_traveling_actor_ids AS (
|
|
SELECT id FROM traveling_actor_ids
|
|
WHERE NOT EXISTS (SELECT 1 FROM invalid_traveling_actor_ids)
|
|
),
|
|
insert_actor_state AS (
|
|
INSERT INTO actor_state(actor_id, state)
|
|
SELECT id, 'Travel' FROM valid_traveling_actor_ids
|
|
ON CONFLICT DO NOTHING
|
|
),
|
|
update_actors AS (
|
|
UPDATE actors
|
|
SET
|
|
transform = in_target_transform,
|
|
dimension_index = in_target_dimension_index,
|
|
map = in_target_map,
|
|
partition_id = in_target_partition_id
|
|
FROM valid_traveling_actor_ids
|
|
WHERE actors.id = valid_traveling_actor_ids.id
|
|
)
|
|
SELECT * FROM invalid_traveling_actor_ids;
|
|
end
|
|
$function$
|
|
|
|
|
|
-- update_universe_time(in_farm_id text) -> TABLE(universe_time_timestamp timestamp without time zone, down_time_accumulation bigint)
|
|
-- oid: 58642 kind: FUNCTION category: schema_meta
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_universe_time(in_farm_id text DEFAULT NULL::text)
|
|
RETURNS TABLE(universe_time_timestamp timestamp without time zone, down_time_accumulation bigint)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
BEGIN
|
|
INSERT INTO farm_variables(farm_id, universe_time_timestamp, universe_lastactive_timestamp, down_time_accumulation, one_row)
|
|
VALUES (in_farm_id, (CURRENT_TIMESTAMP AT TIME ZONE 'UTC')::TIMESTAMP, (CURRENT_TIMESTAMP AT TIME ZONE 'UTC')::TIMESTAMP, 0, true)
|
|
ON CONFLICT(one_row) DO UPDATE
|
|
SET
|
|
down_time_accumulation = CASE
|
|
WHEN farm_variables.farm_id != EXCLUDED.farm_id AND farm_variables.farm_id IS NOT NULL AND EXCLUDED.farm_id IS NOT NULL THEN farm_variables.down_time_accumulation + (EXTRACT(EPOCH FROM ((CURRENT_TIMESTAMP AT TIME ZONE 'UTC')::TIMESTAMP - farm_variables.universe_lastactive_timestamp)) * 1000000)::BIGINT
|
|
ELSE farm_variables.down_time_accumulation
|
|
END,
|
|
universe_lastactive_timestamp = (CURRENT_TIMESTAMP AT TIME ZONE 'UTC')::TIMESTAMP,
|
|
farm_id = CASE
|
|
WHEN EXCLUDED.farm_id IS NULL AND farm_variables.farm_id IS NOT NULL THEN farm_variables.farm_id
|
|
ELSE EXCLUDED.farm_id
|
|
END;
|
|
RETURN QUERY select * from get_universe_time();
|
|
RETURN;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- update_vendor_timestamp_for_player(in_vendor_id text, in_player_id bigint, in_timestamp bigint) -> void
|
|
-- oid: 58643 kind: FUNCTION category: stock_vendor
|
|
|
|
CREATE OR REPLACE FUNCTION dune.update_vendor_timestamp_for_player(in_vendor_id text, in_player_id bigint, in_timestamp bigint)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
IF NOT EXISTS
|
|
( SELECT * FROM vendor_stock_cycle
|
|
WHERE vendor_id = in_vendor_id AND player_id = in_player_id)
|
|
THEN
|
|
INSERT INTO vendor_stock_cycle(vendor_id, player_id, last_interacted_timestamp) VALUES(in_vendor_id, in_player_id, in_timestamp);
|
|
ELSE
|
|
UPDATE vendor_stock_cycle
|
|
SET last_interacted_timestamp = in_timestamp
|
|
WHERE vendor_id = in_vendor_id AND player_id = in_player_id;
|
|
END IF;
|
|
END
|
|
$function$
|
|
|
|
|
|
-- upgrade_location_data_list(in_location_data_list jsonb, in_map_field_name text) -> jsonb
|
|
-- oid: 58644 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.upgrade_location_data_list(in_location_data_list jsonb, in_map_field_name text)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return COALESCE(
|
|
(
|
|
SELECT jsonb_agg(
|
|
CASE
|
|
WHEN elem ? in_map_field_name
|
|
THEN
|
|
jsonb_set(
|
|
elem,
|
|
('{' || in_map_field_name ||'}')::Text[],
|
|
upgrade_map_value(elem->in_map_field_name)
|
|
)
|
|
ELSE
|
|
elem
|
|
END
|
|
)
|
|
FROM jsonb_array_elements(in_location_data_list) elem
|
|
),
|
|
'[]'::jsonb
|
|
);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- upgrade_map_name(in_map_name text) -> text
|
|
-- oid: 58645 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.upgrade_map_name(in_map_name text)
|
|
RETURNS text
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
return
|
|
CASE in_map_name
|
|
WHEN 'Survival_1' THEN 'HaggaBasin'
|
|
WHEN 'SH_HarkoVillage' THEN 'HarkoVillage'
|
|
WHEN 'DeepDesert_1' THEN 'DeepDesert'
|
|
WHEN 'Overmap' THEN 'Overland'
|
|
WHEN 'SH_Arrakeen' THEN 'Arrakeen'
|
|
WHEN 'CB_Story_Hephaestus' THEN 'WreckOfHephaestus'
|
|
WHEN 'CB_Story_Ecolab_Carthag' THEN 'BeneathCarthag'
|
|
WHEN 'CB_SurvivalChallenge_Station_15' THEN 'Station15'
|
|
WHEN 'CB_Story_WaterFatManor' THEN 'WaterFat'
|
|
WHEN 'SH_FallenLight' THEN 'FallenLight'
|
|
WHEN 'Story_ProcesVerbal' THEN 'ProcesVerbal'
|
|
WHEN 'DLC_Story_LostHarvest' THEN 'LostHarvest'
|
|
WHEN 'DLC_Story_LostHarvest_EcolabA' THEN 'LostHarvest_EcolabA'
|
|
WHEN 'DLC_Story_LostHarvest_EcolabB' THEN 'LostHarvest_EcolabB'
|
|
WHEN 'DLC_Story_LostHarvest_ForgottenLab' THEN 'LostHarvest_ForgottenLab'
|
|
WHEN 'Story_ArtOfKanly' THEN 'ArtOfKanly'
|
|
WHEN 'Story_HeighlinerDungeon' THEN 'HeighlinerDungeon'
|
|
WHEN 'CB_Dungeon_Hephaestus' THEN 'WreckOfHephaestusDungeon'
|
|
WHEN 'CB_Dungeon_OldCarthag' THEN 'OldCarthagDungeon'
|
|
WHEN 'CB_Story_BanditFortress01' THEN 'SandfliesFortress'
|
|
WHEN 'CB_Overland_S_05' THEN 'ClosedOffTestingStationIsland'
|
|
WHEN 'CB_Overland_S_06' THEN 'GroundVehicleTimeTrialIsland'
|
|
WHEN 'CB_Overland_S_04' THEN 'ErythriteCaveIsland'
|
|
WHEN 'CB_Overland_M_01' THEN 'RadioactiveShipwreck'
|
|
WHEN 'CB_Overland_S_07' THEN 'TheRuinsOfTsimpo'
|
|
WHEN 'Story_Faction_Outpost_Hark' THEN 'Story_Faction_Outpost_Hark'
|
|
WHEN 'Story_Faction_Outpost_Atre' THEN 'Story_Faction_Outpost_Atre'
|
|
WHEN 'CB_Ecolab_Bronze_Green_089' THEN 'RadiationDungeon'
|
|
WHEN 'CB_Ecolab_Bronze_Green_152' THEN 'ElectricityDungeon'
|
|
WHEN 'CB_Ecolab_Bronze_Green_195' THEN 'PoisonDungeon'
|
|
WHEN 'CB_Ecolab_Bronze_Green_024' THEN 'DarknessDungeon'
|
|
WHEN 'CB_Ecolab_Bronze_Green_136' THEN 'FireDungeon'
|
|
WHEN 'CB_Story_DestroyedZanovar' THEN 'DestroyedZanovar'
|
|
WHEN 'CB_Story_OrbitalMonitor' THEN 'OrbitalMonitor'
|
|
WHEN 'CB_Dungeon_TheFacility' THEN 'FacilityDungeon'
|
|
WHEN 'CB_Dungeon_ThePit' THEN 'PitDungeon'
|
|
WHEN 'CB_Overland_S_08' THEN 'WindPass'
|
|
ELSE in_map_name
|
|
END;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- upgrade_map_value(in_value jsonb) -> jsonb
|
|
-- oid: 58646 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.upgrade_map_value(in_value jsonb)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
RETURN
|
|
CASE
|
|
WHEN jsonb_typeof(in_value) = 'string'
|
|
THEN
|
|
jsonb_build_object('Name', upgrade_map_name(in_value->>0))
|
|
ELSE
|
|
in_value
|
|
END;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- upsert_spicefield_types(in_max_globally_active integer[], in_max_globally_primed integer[], in_field_types text[], in_map_name text, in_dimension_index integer) -> TABLE(type_id integer, max_global integer, max_global_primed integer, spawning_active boolean, out_field_type text)
|
|
-- oid: 58647 kind: FUNCTION category: spice_field
|
|
|
|
CREATE OR REPLACE FUNCTION dune.upsert_spicefield_types(in_max_globally_active integer[], in_max_globally_primed integer[], in_field_types text[], in_map_name text, in_dimension_index integer)
|
|
RETURNS TABLE(type_id integer, max_global integer, max_global_primed integer, spawning_active boolean, out_field_type text)
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
begin
|
|
insert into spicefield_types (max_globally_active, max_globally_primed, field_type, map_name, dimension_index)
|
|
select unnest(in_max_globally_active), unnest(in_max_globally_primed), unnest(in_field_types), in_map_name, in_dimension_index
|
|
on conflict do nothing;
|
|
return query select spicefield_type_id, max_globally_active, max_globally_primed, is_spawning_active, field_type::text from spicefield_types where map_name = in_map_name and dimension_index = in_dimension_index;
|
|
end $function$
|
|
|
|
|
|
-- use_sinkchart(in_player_id bigint, in_account_id bigint, in_area_id smallint, in_item_id bigint, in_sinkchart_map_name text, in_player_map_name text, in_player_current_dimension integer) -> dune.usesinkchartreturndata
|
|
-- oid: 58648 kind: FUNCTION category: map_areas
|
|
|
|
CREATE OR REPLACE FUNCTION dune.use_sinkchart(in_player_id bigint, in_account_id bigint, in_area_id smallint, in_item_id bigint, in_sinkchart_map_name text, in_player_map_name text, in_player_current_dimension integer)
|
|
RETURNS dune.usesinkchartreturndata
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
sinkchart_markers SinkchartMarkerData[];
|
|
survey_target JSONB;
|
|
BEGIN
|
|
-- Update map areas.
|
|
INSERT INTO map_areas (account_id, time_first_entered, time_discovered, area_id, items_surveyed_target, map_name)
|
|
SELECT in_account_id, NULL, NOW(), in_area_id, map_areas.items_surveyed_target, in_sinkchart_map_name
|
|
FROM map_areas
|
|
WHERE map_areas.area_id = in_area_id
|
|
AND map_areas.map_name = in_sinkchart_map_name
|
|
AND map_areas.items_surveyed_target IS NOT NULL
|
|
LIMIT 1
|
|
ON CONFLICT ON CONSTRAINT map_areas_pkey DO UPDATE
|
|
SET items_surveyed_target = EXCLUDED.items_surveyed_target,
|
|
time_discovered = CASE WHEN map_areas.time_discovered IS NULL THEN EXCLUDED.time_discovered ELSE map_areas.time_discovered END
|
|
RETURNING items_surveyed_target INTO survey_target;
|
|
|
|
-- Perform the INSERT operation explicitly.
|
|
INSERT INTO player_markers (player_id, marker_hash_id, dimension_index, map_name_id, discovery_level, discovery_method, payload)
|
|
SELECT DISTINCT ON (m.marker_hash_id, m.dimension_index)
|
|
in_player_id, m.marker_hash_id, m.dimension_index, m.map_name_id, /*discovery_level*/ 2, /*discovery_method*/ 12, /*payload*/ '{}'::JSONB
|
|
FROM (
|
|
SELECT UNNEST(sc.marker_hash_ids) AS marker_hash_id
|
|
FROM sinkcharts sc
|
|
WHERE sc.item_id = in_item_id
|
|
) expanded_ids
|
|
JOIN map_names mn
|
|
ON mn.map_name = in_sinkchart_map_name
|
|
INNER JOIN markers m
|
|
ON expanded_ids.marker_hash_id = m.marker_hash_id AND m.map_name_id = mn.map_name_id
|
|
ORDER BY m.marker_hash_id, m.dimension_index
|
|
ON CONFLICT ON CONSTRAINT player_markers_pkey DO UPDATE
|
|
SET discovery_level = GREATEST(player_markers.discovery_level, EXCLUDED.discovery_level);
|
|
|
|
-- Get markers that should be shown to the player immediately (marker on same map and dimension).
|
|
SELECT ARRAY_AGG(ROW(m.marker_hash_id, m.marker, m.area_id, m.area_radius, m.long_range, pm.payload, m.payload)::SinkchartMarkerData)
|
|
INTO sinkchart_markers
|
|
FROM (
|
|
SELECT UNNEST(sc.marker_hash_ids) AS marker_hash_id
|
|
FROM sinkcharts sc
|
|
WHERE sc.item_id = in_item_id
|
|
) expanded_ids
|
|
JOIN map_names smn
|
|
ON smn.map_name = in_sinkchart_map_name
|
|
INNER JOIN markers m
|
|
ON expanded_ids.marker_hash_id = m.marker_hash_id AND m.map_name_id = smn.map_name_id
|
|
INNER JOIN player_markers pm
|
|
ON m.marker_hash_id = pm.marker_hash_id
|
|
AND m.dimension_index = pm.dimension_index
|
|
AND m.map_name_id = pm.map_name_id
|
|
AND pm.player_id = in_player_id
|
|
JOIN map_names pmn
|
|
ON pmn.map_name = in_player_map_name
|
|
WHERE m.map_name_id = pmn.map_name_id
|
|
AND (m.dimension_index = -1 OR m.dimension_index = in_player_current_dimension);
|
|
|
|
RETURN (sinkchart_markers, survey_target);
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- verify_item_dup_backup_tool(in_account_id bigint, in_vehicle_id bigint, in_cheat_type dune.cheat_type_enum) -> void
|
|
-- oid: 58649 kind: FUNCTION category: inventory
|
|
|
|
CREATE OR REPLACE FUNCTION dune.verify_item_dup_backup_tool(in_account_id bigint, in_vehicle_id bigint, in_cheat_type dune.cheat_type_enum)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
DECLARE
|
|
v_FLS_id TEXT;
|
|
BEGIN
|
|
PERFORM 1 FROM inventories inv JOIN items it ON it.inventory_id = inv.id WHERE inv.actor_id = in_vehicle_id;
|
|
IF FOUND THEN
|
|
|
|
-- Delete all items in this vehicle's inventories (excluding module inventories)
|
|
PERFORM delete_items(
|
|
(
|
|
SELECT array_agg(i.id)
|
|
FROM items i
|
|
JOIN inventories inv ON inv.id = i.inventory_id
|
|
WHERE inv.actor_id = in_vehicle_id
|
|
AND inv.inventory_type = 0 -- 0 = vehicle backpack
|
|
)
|
|
);
|
|
|
|
-- Debug logging
|
|
SELECT acc."user"
|
|
INTO v_FLS_id
|
|
FROM accounts acc
|
|
WHERE acc.id = in_account_id
|
|
LIMIT 1;
|
|
RAISE WARNING 'Trying to vbt vehicle that has not an empty inventory. Behavior: % Vehicle: %, Account: %, FLS: %', in_cheat_type, in_vehicle_id, in_account_id, v_FLS_id;
|
|
|
|
-- DB tracking
|
|
PERFORM log_cheating(v_FLS_id, in_cheat_type);
|
|
|
|
END IF;
|
|
END;
|
|
$function$
|
|
|
|
|
|
-- wipe_old_events_log(in_days_limit integer) -> void
|
|
-- oid: 58650 kind: FUNCTION category: cleanup
|
|
|
|
CREATE OR REPLACE FUNCTION dune.wipe_old_events_log(in_days_limit integer)
|
|
RETURNS void
|
|
LANGUAGE plpgsql
|
|
AS $function$
|
|
BEGIN
|
|
DELETE FROM game_events WHERE universe_time < to_timestamp(in_days_limit);
|
|
END
|
|
$function$
|
|
|
|
|
|
-- zero_transform() -> dune.transform
|
|
-- oid: 58651 kind: FUNCTION category: misc
|
|
|
|
CREATE OR REPLACE FUNCTION dune.zero_transform()
|
|
RETURNS dune.transform
|
|
LANGUAGE plpgsql
|
|
IMMUTABLE
|
|
AS $function$
|
|
BEGIN
|
|
RETURN (
|
|
ROW(
|
|
ROW(0.0, 0.0, 0.0)::Vector,
|
|
ROW(0.0, 0.0, 0.0, 1.0)::Quaternion
|
|
)::Transform
|
|
);
|
|
END;
|
|
$function$
|