Livre-se dos ciclos usuais de MUD

7

Estou trabalhando em um mecanismo de MUD e quero fazê-lo de maneira um pouco diferente de todos os jogos de MUD que joguei. Eu acho um sistema de "ciclo" muito chato. Uma das idéias que tive foi fazer com que todos os soquetes de clientes funcionassem em seu próprio Thread. Estou ciente de que não terminará com centenas de reprodutores, mas gostaria de saber se há problemas ao criar "um monte" de encadeamentos em um único processo.

Ou que outra estratégia eu poderia usar se quisesse fazer isso (por exemplo, combates) em "tempo real".

Espero que vocês entendam a pergunta.

Obrigado.

Cybrix
fonte

Respostas:

14

Os ciclos de MUD geralmente não existem, porque o servidor tem problemas para processar tudo dentro do tempo disponível ou atender às solicitações de rede com rapidez suficiente. Eles estão lá porque os comandos de spam o mais rápido possível não devem ser uma tática válida.

Basta ter um timer de recarga / recarga associado a cada habilidade. Dependendo do seu design social, isso também pode incluir "mover" e "falar", ou não.

Geralmente, ter mais de um encadeamento por núcleo para processamento de rede em um jogo é inútil. Se você está vinculado ao processamento de pacotes, um encadeamento por núcleo estará maximizando seu sistema - mais encadeamentos acabariam deixando o restante do tempo de CPU necessário. Se você não está vinculado ao processamento de pacotes, um encadeamento por núcleo é pequeno o suficiente para não afetar o restante do sistema através de muitas opções de contexto.


fonte
Exatamente o que esta pessoa disse :)
speeder
3
Porra, entre na coisa ... Enfim, eu vi uma vez um MUD sem ciclo, e foi péssimo, porque alguns jogadores faziam macros estranhas em seus clientes, e quando você ia ao PvP com eles, eles facilmente batiam em você por pura morte. comando de inundação, mesmo que fossem mais fracos, às vezes batiam em você várias vezes antes que você tivesse a chance de ler o que estava acontecendo.
speeder
Hmm, eu entendo o ponto, mas adicionando comandos diferentes, um atraso interno (comando de combate 3s, movimento digamos 2s e socials 1s). Eu acredito que isso resolveria esse problema. Os outros textos de batalhas serão exibidos constantemente. Alguns jogadores acertam mais / mais rápido, dependendo de suas estatísticas. Isso é o meu pensamento de que eu gostaria de fazer
Cybrix
essa foi a ideia por trás da coisa toda. Eu simplesmente não consigo descobrir se tudo roda no mesmo thread único. Parece um grande loop para mim ver se algum jogador tem um comando em buffer e depois executá-lo. Mas e os comandos de ataques regulares (semelhante ao "dano branco" no WoW)?
Cybrix
Execute a atualização da lógica do jogo em alguns FPS fixos, por exemplo, 30. Dano que ocorre a cada 2 segundos ocorre a cada 60 quadros. É apenas um loop de jogo normal, mas sem a chamada render ().
5

Desculpe pela necromancia do encadeamento, mas esse problema é meu projeto favorito para aprender e ensinar modelos e estruturas de simultaneidade!

A execução de cada cliente / mob em seu próprio encadeamento gera uma divisão natural, mas como vários observaram, os encadeamentos são caros quando você usa mais deles do que os núcleos da CPU. Se esse não é um motivo convincente para não usá-lo no seu MUD, ainda é um bom motivo para aprender uma maneira melhor.

A execução de todos os clientes em um único ciclo de jogo em tempo fixo, com ações executando um certo número de loops, é um método familiar do mundo dos jogos gráficos. Ele vincula tudo no mundo ao mesmo ciclo de tempo, embora fazer os loops suficientemente refinados possa mascarar isso. A principal desvantagem desse método, a meu ver, é que ele não é inerentemente paralelamente agradável. Alguém observou que você pode criar threads para descarregar a E / S de construção / análise / transcepção, executando a IA e outros para outros segmentos, mas tornar a lógica do jogo principal paralelizada exige uma mudança fundamental e muito trabalho para manter as coisas seguras.

Se você fizesse todo esse trabalho, provavelmente terminaria com algo parecido com o meu favorito atual, o modelo de ator ( http://en.wikipedia.org/wiki/Actor_model ). O modelo Actor é uma estratégia de compartilhamento de tempo que acaba elaborando bem próximo do que você estava propondo com a idéia de um thread por cliente. Ao usá-lo, você codifica seus "Atores" como se fossem threads independentes, com algumas restrições: eles devem ser controlados por eventos e só podem se comunicar com o resto do sistema passando mensagens (o que é diferente, mas simples). O bit orientado a eventos abre espaço para o seu tempo verdadeiramente independente, agendando eventos específicos do ator para serem disparados em momentos específicos, por exemplo, quando uma ação é concluída ou em alguma frequência específica do cliente.

Sob o capô, a implementação usa uma fila (ou filas) de mensagens sendo geradas por todos os atores e um conjunto de encadeamentos que correspondem ao número de núcleos da CPU. Os encadeamentos retiram as mensagens das filas e invocam os métodos de manipulação de mensagens do Ator destinatário para manipulá-los, executando no contexto desse Ator até que a mensagem seja "manipulada". Do seu ponto de vista, cada Ator obtém seu próprio encadeamento sempre que está em execução, mas, do ponto de vista do sistema, existem apenas quantos encadeamentos há CPUs para executá-los.

Existem algumas estruturas ótimas de atores por aí, como Erlang / OTP e Akka, mas a idéia básica é simples o suficiente para que você possa implementá-la em qualquer idioma sem o barulho adicional de uma estrutura.

Para ser completo, o modelo Actor é realmente apenas a combinação de passagem de mensagens para segurança de encadeamento, programação orientada a eventos para simultaneidade e um mecanismo de envio de encadeamento. Se você remover os bits de despacho de threads, ficará com um sistema "reativo", que está em voga para a escalabilidade em geral no momento (consulte http://www.reactivemanifesto.org/ ). Você pode mapear a execução para várias máquinas em uma nuvem ou o que quer que seja ... você entendeu ... o que significa dizer que seu projeto de programação MUD pode estar lhe ensinando habilidades de programação comercializáveis. Viva!

SAyotte
fonte
2

Você pode permitir comandos de combate quando eles chegarem e, em seguida, adicionar um atraso de tempo após os comandos, com base em quanto tempo eles levariam para executar.

Dragonrealms usa esse método de combate, assim como muitas outras ações, é chamado Roundtime por lá. Armas mais pesadas ganham mais tempo e você pode reduzi-las, mas não eliminá-las com força e agilidade.

lathomas64
fonte
Essa é exatamente a minha ideia por trás. Mas eu pensei que iria dirigi-lo com clientes multiencadeados. Mas agora ouço que não é uma boa sugestão: P
Cybrix 9/10/10
por que usar threads além do que você pode usar para soquetes / comunicação?
usar o seguinte comando
0

A rede é de natureza serial de qualquer maneira (pelo menos até você entrar em linhas de fibra óptica multi-Tbps). Ter um encadeamento para E / S de rede separado da lógica do jogo e talvez alguns encadeamentos autônomos de agente fazem sentido. Tudo o resto é um exagero.

Martin Sojka
fonte
Se você possui máquinas multicore, recomendo mais de um encadeamento de rede (até um por núcleo); enquanto cada soquete é limitado pela rede, a leitura das solicitações do cliente e a construção dos pacotes de estado do jogo / resposta RPC para empurrar de volta para os soquetes é quase perfeitamente paralelista.