Agathos, caetanoweb, hadeslan, Mentor, sula, viniciusvj, viOleNt, Yago
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
Última edição por Renato; 23-01-2017 às 09:14 AM.
Código PHP:
<?php
if(Weather::getState() == 'Rainy weather') {
$this->removingLittleHorseFromRain();
}
Agathos, caetanoweb, hadeslan, Mentor, sula, viniciusvj, viOleNt, Yago
Se quiser que eu ti ajude
Posso por em teste em meu servidor o mesmo está off ainda apenas Online para mim e equipe.
Season6 ep 3 x-team.
"Só tem o direito de criticar aqueles, que pretendem ajudar "
Refiz todas as querys e testei. Aparentemente está perfeito.
Qualquer dúvida ou problema reportem aqui.
[]'s
Código PHP:
<?php
if(Weather::getState() == 'Rainy weather') {
$this->removingLittleHorseFromRain();
}
Qual o código pra por no ranking do site ? só usa TimeON mas e pra deixar os minutos?
vou testar aqui, já posto novidades !
Sugestão #1:
Na trigger, eu não testei, mas o que aconteceria no caso de a pessoa logar, ter por exemplo 1 ou mais chars criados e simplesmente deletar um deles?
Pela descrição da query, esse caso não foi tratado, nem sei se o GameIDC seria ou não atualizado. (só testando mesmo)
Nada grave, mas, não custa nada dar uma olhada né?
Sugestão #2:
Em vez de usar vários declares, pode resumir tudo em um...
Código:DECLARE @Find_ID VARCHAR(10); DECLARE @ConnectStat TINYINT; DECLARE @LoginTime INT; DECLARE @LogoutTime INT; DECLARE @ConnectTM INT;Sugestão 3:Código:DECLARE @Find_ID VARCHAR(10), @ConnectStat TINYINT, @LoginTime INT, @LogoutTime INT, @ConnectTM INT, @DisConnectTM INT, @TimeON_Account BIGINT, ...
Isso é equivalente a isto:Código:SET @ConnectTM = (SELECT DATEDIFF(s, '19700101', MEMB_STAT.ConnectTM) FROM MEMB_STAT WHERE memb___id = @memb___id); SET @DisConnectTM = DATEDIFF(s, '19700101', @Now);
Tem que tratar o retorno do DATEDIFF também, não acredito que vá existir um intervalo de tempo tão grande.Código:SELECT @TimeON_Account = DATEDIFF(SECOND, ConnectTM, @Now) FROM MEMB_STAT WHERE memb___id = @memb___id;
Apesar que você já sabe né? No MU tudo de errado é possível e sempre acontece...
Seria preciso ajustar também para @Now.
Pelo que eu olhei por cima, só isso.
-- EDIT --
Ah parece que tem uma referência pro @DisConnectTM mais no final:
[]'sCódigo:SET @TimeON_Char = (@DisConnectTM - @CharConnectTM_Int);
@navossoc obrigado pelas sugestões.
Com relação à #1, já foi tratado. Se o cara deleta ou cria um char, não há update na GameIDC, apenas na GameID respectiva, então isso "IF UPDATE(GameIDC) BEGIN" já resolve.
Contudo, embora não seja a mesma situação que você mencionou (pois falou apenas sobre "deletar um char"), sua sugestão me chamou a atenção para uma situação que eu não havia pensado:
- Se o cara acessa um char (GameIDC é atualizado para o nick desse char), depois clica em "Selecionar personagem", apaga esse char e acessa um outro char logo após ter deletado esse char, a trigger não vai funcionar corretamente, pois iria dar "update" do tempo on de um char que não existe mais na Character, no caso o @Old_GameIDC.
Vou por uma checagem de existência do char @Old_GameIDC dentro do IF da hipótese 1.1.2.
Sobre as demais sugestões, vou analisar.
Grato novamente pelas sugestões @navossoc.
[]'s
----------------------------
UPDATE 1.
TRIGGER atualizada para versão 2.1.1. Correção do problema:
Sugestão #2 aplicada.
Sobre a sugestão #3, vou analisar aqui.
Com relação a tratar o retorno DATEDIFF, acha realmente necessário @navossoc? Seria muita doidera um intervalo maior que 68 anos.
Última edição por Renato; 29-08-2015 às 03:41 PM.
Código PHP:
<?php
if(Weather::getState() == 'Rainy weather') {
$this->removingLittleHorseFromRain();
}
A sugestão #1 era bem esse caso mesmo, quando eu falei eu pensei nessa situação, atualizar um personagem que não existe.
Apesar que isso não acontece pois como você mesmo disse não atualiza o GameIDC, mas, serviu de qualquer maneira.
Acabei de ler a documentação, realmente são 68 anos, acho que está sossegado então :P
[]'s
@navossoc sim.
Ao que parece essa vai ficar como versão final da query mesmo. Não vislumbro necessidade de mais modificações.
![]()
Código PHP:
<?php
if(Weather::getState() == 'Rainy weather') {
$this->removingLittleHorseFromRain();
}
Há 1 usuários navegando neste tópico. (0 registrados e 1 visitantes)
Marcadores