PDA

View Full Version : |Jobs/Query| Contagem de tempo online de conta + char (HOT)



cronusmaker
12-08-2022, 12:50 PM
funciona melhor em sql 2008+


Há tempos vejo pessoas pedindo query pra contar tempo online de char, então resolvi por a mão na massa e fazer uma.


Se houver bugs eu fixo, só avisar aqui, mas aparentemente está 100% (fiz inúmeros testes).[B]


A contagem é feita em segundos e é armazenada:


- Tempo da conta: na MEMB_INFO, coluna TimeON.
- Tempo de cada char: na Character, coluna TimeON.




O tempo online é atualizado:


- Quando você seleciona char (mesmo se não trocar de char).
- Quando você troca de char.
- Quando você desloga a conta.


Vamos lá.




[B]♦ Versões atuais dos Scripts:


- TRIGGER: 2.1.2
- WZ_DISCONNECT_MEMB: 2.0.0




[B]♦ ALTER TABLES


USE [MUOnline]GO
ALTER TABLE [dbo].[MEMB_STAT]ALTER COLUMN [ConnectTM] [datetime] NULLGO
ALTER TABLE [dbo].[MEMB_STAT]ALTER COLUMN [DisConnectTM] [datetime] NULLGO
ALTER TABLE [dbo].[MEMB_INFO]ADD [TimeON] [bigint] NOT NULL DEFAULT 0GO
ALTER TABLE [dbo].[Character]ADD [ConnectTM] [datetime] NULLGO
ALTER TABLE [dbo].[Character]ADD [DisConnectTM] [datetime] NULLGO
ALTER TABLE [dbo].[Character]ADD [TimeON] [bigint] DEFAULT ((0)) NOT NULLGO



♦ TRIGGER - AccountCharacter_Online



/*| @author - Renato Valer| @version - 2.1.2| @last update - 2016/02/12 - 08h18min| @warning: Não me responsabilizo por uso incorreto e possíveis deadlocks. Use por sua conta e risco.*/
USE MuOnlineGO
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'AccountCharacter_Online' AND type = 'TR') DROP TRIGGER [AccountCharacter_Online]GO
CREATE TRIGGER [AccountCharacter_Online] ON [dbo].[AccountCharacter] AFTER UPDATE AS SET NOCOUNT ON
/*| Hipóteses| || 1 - Se GameIDC foi atualizado, algum char foi foi logado. Surgem hipóteses:|| 1.1 - GameIDC e Old_GameIDC são diferentes:| | 1.1.1 - Old_GameIDC é NULL, logo é o primeiro char logado (e possivelmente o primeiro criado) na conta, | pois não existe GameIDC anterior.| 1.1.2 - Já existe um GameIDC anterior, logo significa que o cara acessou outro char. Surgem 2 hipóteses:|| 1.1.2.1 - O cara simplesmente trocou de char sem deslogar a conta:| 1.1.2.1.1 - O cara logou um char, deletou ele e entrou em outro.| 1.1.2.2 - O cara relogou a conta e entrou em outro char.| 1.1.2.2.1 - O cara logou um char, deletou ele, saiu da conta, voltou e entrou em outro.| | 1.2 GameIDC e Old_GameIDC são iguais:| | 1.2.1 - O cara relogou o char.| 1.2.2 - O cara relogou a conta e entrou no mesmo char.|| 2. Se GameIDC não foi atualizado, não precisa fazer nada, porque significa:| | 2.1 - Que um char foi criado, mas não foi logado.| 2.2 - Que um char foi deletado sem nem mesmo ter sido logado.| | */
-- Hipótese 1IF UPDATE(GameIDC) BEGIN
DECLARE @Login VARCHAR(10), @GameIDC VARCHAR(10), @Old_GameIDC VARCHAR(10), @GameIDC_ConnectTM DATETIME, @GameIDC_ConnectTM_Int INT, @Old_GameIDC_ConnectTM DATETIME, @Old_GameIDC_ConnectTM_Int INT, @GameIDC_DisConnectTM DATETIME, @GameIDC_DisConnectTM_Int INT, @Old_GameIDC_DisConnectTM DATETIME, @Old_GameIDC_DisConnectTM_Int INT, @account_DisconnectTM DATETIME, @account_DisconnectTM_Int INT, @Now DATETIME, @Now_Int INT, @TimeON BIGINT;
SET @Login = (SELECT Id FROM INSERTED); SET @GameIDC = (SELECT GameIDC FROM AccountCharacter WHERE Id = @Login); SET @Old_GameIDC = (SELECT GameIDC FROM DELETED); SET @Now = GETDATE(); SET @Now_Int = DATEDIFF(s, '19700101', @Now); SET @account_DisconnectTM = (SELECT DisconnectTM FROM MEMB_STAT WHERE memb___id = @Login); SET @account_DisconnectTM_Int = DATEDIFF(s, '19700101', @account_DisconnectTM);
-- Hipótese 1.1 IF(@GameIDC <> @Old_GameIDC) BEGIN
-- Hipótese 1.1.1 IF(@Old_GameIDC IS NULL) BEGIN UPDATE Character SET ConnectTM = @Now WHERE AccountID = @Login AND Name = @GameIDC; END -- Hipótese 1.1.2 ELSE BEGIN SET @Old_GameIDC_DisconnectTM = @Now SET @Old_GameIDC_DisconnectTM_Int = @Now_Int; -- Hipótese 1.1.2.1 IF @account_DisconnectTM_Int <> @Old_GameIDC_DisconnectTM_Int) BEGIN -- Verificação da Hipótese 1.1.2.1.1 IF EXISTS(SELECT Name FROM Character WHERE AccountID = @Login AND Name = @Old_GameIDC) BEGIN
SET @Old_GameIDC_ConnectTM = (SELECT ConnectTM FROM Character WHERE AccountID = @Login AND Name = @Old_GameIDC); SET @Old_GameIDC_ConnectTM_Int = DATEDIFF(s, '19700101', @Old_GameIDC_ConnectTM); SET @TimeON = @Old_GameIDC_DisconnectTM_Int - @Old_GameIDC_ConnectTM_Int; UPDATE Character SET TimeON = TimeON + @TimeON, DisConnectTM = @Now WHERE AccountID = @Login AND Name = @Old_GameIDC; END END -- Hipótese 1.1.2.2 e "fim" da Hipótese 1.1.2.1 -- A query é a mesma e um "else" é desnecessário. /* | Não é necessário atualizar tempo on, porque se o cara relogou a conta | a WZ_DISCONNECT_MEMB já fez o serviço. Só precisamos atualizar o momento | de connect do novo char. */ UPDATE Character SET ConnectTM = @Now WHERE AccountID = @Login AND Name = @GameIDC; END END --Hipótese 1.2. ELSE BEGIN -- Apenas precaução... IF(@GameIDC IS NOT NULL) BEGIN /* | Desnecessário checar se o char existe, porque se essa parte | do script está sendo executada, é porque o char foi logado | agora, logo é presumível que existe. */ SET @GameIDC_ConnectTM = (SELECT ConnectTM FROM Character WHERE AccountID = @Login AND Name = @GameIDC); SET @GameIDC_ConnectTM_Int = DATEDIFF(s, '19700101', @GameIDC_ConnectTM); SET @GameIDC_DisconnectTM_Int = @Now_Int;
-- Hipótese 1.2.1 IF @account_DisconnectTM_Int < @GameIDC_ConnectTM_Int) BEGIN SET @TimeON = @GameIDC_DisconnectTM_Int - @GameIDC_ConnectTM_Int; UPDATE Character SET TimeON = TimeON + @TimeON, DisConnectTM = @Now, ConnectTM = @Now WHERE AccountID = @Login AND Name = @GameIDC; END -- Hipótese 1.2.2 ELSE BEGIN /* Não é necessário atualizar tempo on, porque se o cara relogou a conta a WZ_DISCONNECT_MEMB já fez o serviço. */ UPDATE Character SET ConnectTM = @Now WHERE AccountID = @Login AND Name = @GameIDC; END END END SET NOCOUNT OFFEND



♦ PROCEDURE WZ_DISCONNECT_MEMB




/*| @modifications - Renato Valer| @version - 2.0.0| @last update - 2015/08/28 - 09h25min| @warning: Não me responsabilizo por uso incorreto e possíveis deadlocks. Use por sua conta e risco.*/
USE MuOnlineGO
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'WZ_DISCONNECT_MEMB')DROP PROCEDURE [DBO].[WZ_DISCONNECT_MEMB]GO
CREATE PROCEDURE [DBO].[WZ_DISCONNECT_MEMB] @memb___id VARCHAR(10) AS BEGIN
SET NOCOUNT ON
DECLARE @Find_ID VARCHAR(10),@ConnectStat TINYINT,@LoginTime INT,@LogoutTime INT,@ConnectTM INT,@DisConnectTM INT,@TimeON_Account BIGINT,@TimeON_Char BIGINT,@GameIDC VARCHAR(10),@CharConnectTM DATETIME,@CharConnectTM_Int INT,@Now DATETIME,@Now_Int INT;
SET @ConnectStat = 0SET @Find_ID = 'NOT'SET @Now = GETDATE();
SELECT @Find_ID = S.memb___id FROM MEMB_STAT S INNER JOIN MEMB_INFO I ON S.memb___id COLLATE DATABASE_DEFAULT = I.memb___id WHERE I.memb___id = @memb___id;
IF( @Find_ID <> 'NOT' ) BEGIN
UPDATE MEMB_STAT SET ConnectStat = @ConnectStat, DisconnectTM = @Now WHERE memb___id = @memb___id;

/*Selecionamos os momentos de login e logout da conta e convertemos para números inteiros.*/
SET @ConnectTM = (SELECT DATEDIFF(s, '19700101', MEMB_STAT.ConnectTM) FROM MEMB_STAT WHERE memb___id = @memb___id);SET @DisConnectTM = DATEDIFF(s, '19700101', @Now);

/*Executamos os cálculos para obtermos o tempo total online da conta.*/
SET @TimeON_Account = @DisConnectTM - @ConnectTM;
/*Atualizamos o tempo total online da conta.*/
UPDATE MEMB_INFO SET TimeON = TimeON + @TimeON_Account WHERE memb___id = @memb___id;

/*Selecionando nick do último char logado*/
SET @GameIDC = (SELECT GameIDC FROM AccountCharacter WHERE Id = @memb___id);
/*Algum char foi logado antes de sair da conta.Mesmo que o cara tenha logado na conta e criado o char, o GameIDCsó vai ser preenchido se o cara logar na conta.Sendo assim, se GameIDC for NULL, indica que nenhum charnunca foi logado nessa conta, então não tem necessidade de contar tempo on.*/ IF(@GameIDC IS NOT NULL) BEGIN
/*Verificamos se esse char existe.Motivo: o cara pode ter clicado em "selecionar char", deletado o char e depois deslogado da conta.Se não existe, não precisa fazer nada.*/IF EXISTS (SELECT Name FROM Character WHERE AccountID = @memb___id AND Name = @GameIDC) BEGIN
/*Verificação: quando foi o último connect desse char que acabou de deslogar?Se for nulo, significa que ocorreu algum problema na trigger, entãoadicionamos o valor de "agora" convertido em timestamp para possibilitar o cálculo.*/
SET @CharConnectTM = (SELECT ConnectTM FROM Character WHERE AccountID = @memb___id AND Name = @GameIDC);IF (@CharConnectTM IS NULL) BEGINSET @CharConnectTM_Int = DATEDIFF(s, '19700101', @Now);END/*Se não for nulo, convertemos para timestamp.*/ELSE BEGINSET @CharConnectTM_Int = DATEDIFF(s, '19700101', @CharConnectTM);END
/*Executamos os cálculos para obtermos o tempo total onlinedo último char logado.*/
SET @TimeON_Char = (@DisConnectTM - @CharConnectTM_Int);
/*Atualizamos o tempo total online do último char logado.*/
UPDATE Character SET TimeON = TimeON + @TimeON_Char, DisConnectTM = @Now WHERE AccountID = @memb___id AND Name = @GameIDC;
ENDENDENDSET NOCOUNT OFFEND





ATENÇÃO




Não me responsabilizo por uso incorreto.
Não me responsabilizo por eventuais deadlocks. Usem por conta e risco.


Agradecimentos a @navossoc (https://bau.perfectzone.com.br/member.php?u=230), @Willerson, @Erick-Master e @viOleNt (https://bau.perfectzone.com.br/member.php?u=3114) pela colaboração.


[]'s


Creditos Renato ( Imperyus )

AnDeR
04-09-2023, 02:52 AM
aqui deu erro

Msg 102, Level 15, State 1, Procedure AccountCharacter_Online, Line 80
Incorrect syntax near ')'.
Msg 102, Level 15, State 1, Procedure AccountCharacter_Online, Line 123
Incorrect syntax near ')'.
Msg 156, Level 15, State 1, Procedure AccountCharacter_Online, Line 130
Incorrect syntax near the keyword 'ELSE'.