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).
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á.
♦ Versões atuais dos Scripts:
- TRIGGER: 2.1.2
- WZ_DISCONNECT_MEMB: 2.0.0
♦ ALTER TABLES
Código:
USE [MUOnline]
GO
ALTER TABLE [dbo].[MEMB_STAT]
ALTER COLUMN [ConnectTM] [datetime] NULL
GO
ALTER TABLE [dbo].[MEMB_STAT]
ALTER COLUMN [DisConnectTM] [datetime] NULL
GO
ALTER TABLE [dbo].[MEMB_INFO]
ADD [TimeON] [bigint] NOT NULL DEFAULT 0
GO
ALTER TABLE [dbo].[Character]
ADD [ConnectTM] [datetime] NULL
GO
ALTER TABLE [dbo].[Character]
ADD [DisConnectTM] [datetime] NULL
GO
ALTER TABLE [dbo].[Character]
ADD [TimeON] [bigint] DEFAULT ((0)) NOT NULL
GO
♦ TRIGGER - AccountCharacter_Online
Código:
/*
| @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 MuOnline
GO
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 1
IF 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 OFF
END
♦ PROCEDURE WZ_DISCONNECT_MEMB
Código:
/*
| @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 MuOnline
GO
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 = 0
SET @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 GameIDC
só vai ser preenchido se o cara logar na conta.
Sendo assim, se GameIDC for NULL, indica que nenhum char
nunca 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ão
adicionamos 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) BEGIN
SET @CharConnectTM_Int = DATEDIFF(s, '19700101', @Now);
END
/*
Se não for nulo, convertemos para timestamp.
*/
ELSE BEGIN
SET @CharConnectTM_Int = DATEDIFF(s, '19700101', @CharConnectTM);
END
/*
Executamos os cálculos para obtermos o tempo total online
do ú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;
END
END
END
SET NOCOUNT OFF
END
ATENÇÃO
Não me responsabilizo por uso incorreto.
Não me responsabilizo por eventuais deadlocks. Usem por conta e risco.
Agradecimentos a @navossoc, @Willerson, @Erick-Master e @viOleNt pela colaboração.
[]'s