-- LegacyWorlds Beta 6 -- PostgreSQL database scripts -- -- Game updates - control functions -- -- Copyright(C) 2004-2010, DeepClone Development -- -------------------------------------------------------- -- -- Start a tick -- CREATE OR REPLACE FUNCTION sys.start_tick( OUT tick_id BIGINT ) STRICT VOLATILE SECURITY DEFINER AS $$ DECLARE n_tick BIGINT; c_tick BIGINT; BEGIN -- Get next / current tick SELECT INTO n_tick , c_tick next_tick , current_tick FROM sys.status WHERE maintenance_start IS NULL FOR UPDATE; IF NOT FOUND OR c_tick IS NOT NULL THEN tick_id := NULL; RETURN; END IF; -- Prepare game updates UPDATE sys.updates SET last_tick = n_tick , status = 'FUTURE' WHERE last_tick < n_tick; -- Update system status UPDATE sys.status SET current_tick = n_tick , next_tick = n_tick + 1; tick_id := n_tick; END; $$ LANGUAGE plpgsql; GRANT EXECUTE ON FUNCTION sys.start_tick( ) TO :dbuser; -- -- Marks a tick as completed -- CREATE OR REPLACE FUNCTION sys.end_tick( IN tick_id BIGINT ) RETURNS VOID STRICT VOLATILE SECURITY DEFINER AS $$ BEGIN UPDATE events.events SET status = 'READY' WHERE status = 'TICK' AND tick = tick_id; UPDATE sys.status SET current_tick = NULL; PERFORM msgs.deliver_internal( ); END; $$ LANGUAGE plpgsql; GRANT EXECUTE ON FUNCTION sys.end_tick( BIGINT ) TO :dbuser; -- -- Check if a tick got "stuck" -- CREATE OR REPLACE FUNCTION sys.check_stuck_tick( OUT tick_id BIGINT ) STRICT VOLATILE SECURITY DEFINER AS $$ DECLARE c_tick BIGINT; u_count INT; BEGIN -- Get next / current tick SELECT INTO c_tick current_tick FROM sys.status WHERE maintenance_start IS NULL FOR UPDATE; IF NOT FOUND OR c_tick IS NULL THEN tick_id := NULL; RETURN; END IF; -- Are there any updates left? SELECT INTO u_count count(*) FROM sys.updates WHERE status = 'FUTURE' AND last_tick = c_tick; IF u_count = 0 THEN PERFORM sys.end_tick( c_tick ); tick_id := NULL; ELSE tick_id := c_tick; END IF; END; $$ LANGUAGE plpgsql; GRANT EXECUTE ON FUNCTION sys.check_stuck_tick( ) TO :dbuser; -- -- Prepare game updates -- -- Parameters: -- u_id Current update identifier -- u_type Type of game updates to prepare -- -- Returns: -- has_more TRUE if there are more updates, FALSE otherwise -- CREATE OR REPLACE FUNCTION sys.prepare_updates( IN u_id BIGINT , IN u_type update_type , OUT has_more BOOLEAN ) STRICT VOLATILE SECURITY DEFINER AS $$ BEGIN UPDATE sys.updates SET status = 'PROCESSING' WHERE id IN ( SELECT id FROM sys.updates WHERE gu_type = u_type AND last_tick = u_id AND status = 'FUTURE' ORDER BY id LIMIT sys.get_constant( 'game.batchSize' )::BIGINT ); has_more := FOUND; END; $$ LANGUAGE plpgsql; GRANT EXECUTE ON FUNCTION sys.prepare_updates( BIGINT , update_type ) TO :dbuser; -- -- Execute procedural game updates -- -- Parameters: -- c_tick Current tick identifier -- u_type Type of updates to execute -- CREATE OR REPLACE FUNCTION sys.exec_update_proc( IN c_tick BIGINT , IN u_type update_type ) RETURNS VOID STRICT VOLATILE SECURITY DEFINER AS $$ BEGIN EXECUTE 'SELECT sys.process_' || lower( u_type::TEXT ) || '_updates( $1 )' USING c_tick; END; $$ LANGUAGE plpgsql; GRANT EXECUTE ON FUNCTION sys.exec_update_proc( BIGINT , update_type ) TO :dbuser; -- -- Mark updates as processed -- -- Parameters: -- c_tick Current tick identifier -- u_type Type of updates to execute -- CREATE OR REPLACE FUNCTION sys.updates_processed( IN c_tick BIGINT , IN u_type update_type ) RETURNS VOID STRICT VOLATILE SECURITY DEFINER AS $$ UPDATE sys.updates SET status = 'PROCESSED' WHERE status = 'PROCESSING' AND last_tick = $1 AND gu_type = $2 $$ LANGUAGE SQL; GRANT EXECUTE ON FUNCTION sys.updates_processed( BIGINT , update_type ) TO :dbuser;