SOP aplicado em um jogo tipo de corrida usando a arquitetura cliente e servidor Alisson Rafael Appio [email protected] Descrição da Aplicação Um jogo tipo de carrinho, onde cada usuário controla o seu carrinho (telcas up, down, left e right) Arquitetura cliente/servidor Em Java Cada movimento do carrinho de um usuário é enviado aos outros usuários (clientes), mantendo um estado consistente do jogo. 2-11 Descrição do Problema Duas equipes escrevem o código do jogo. A primeira equipe conhece os conceitos necessários para fazer um jogo (lógica de jogo e render). A segunda equipe sabe como replicar os objetos mantendo o estado sincronizado em todos os clientes (multiplayer) As equipes não tem acesso direto ao código da outra equipe, porém a API foi bem definida, separando a camada de jogo da camada de network A equipe de network deve suportar os protocolos TCP/IP e UDP/IP 3-11 Solução Proposta Uma das maneiras de resolver o problema sem adicionar overhead na aplicação é usar técnicas de SOP Usar SOP para adicionar suporte de comunicação de rede (TCP e UDP) ao jogo de corrida Diagrama de classes do cliente – RENDER (entidades do domínio) 5-11 Diagrama de classes do cliente Model + Render 6-11 Diagrama de classe do servidor 7-11 Diagrama de classes do Game Componente (usando SOP) 8-11 Diagrama de classes do Server Componente (Usando SOP) VehicleGameServer +addVehicle(VehicleModel) +removeVehicle(VehicleModel) +updatePosition(VehicleModel) +run() +initialize() +initializeOidTo(VehicleModel) +positionChanged(VehicleModel) +vehicleAdded(VehicleModel) +vehicleRemove(VehicleModel) <<SOP>> VehicleGameServerComponent +setVehicleOid(VehicleModel) +initialize() +initializeOidTo(VehicleModel) +run() +positionChanged(VehicleModel) +vehicleAdded(VehicleModel) +vehicleRemoved(VehicleModel) ServerNetwork 9-11 +sendBroadcast() +startServer() +send() Diagrama de classes do VehicleModel Componente (Usando SOP) 10-11 Diagrama de componente do Server 11-11 Código Component Game public class Game { public void run() { GameThread t = new GameThread(this, renderer); t.setDaemon(true); t.start(); } network = ClientNetwork.instance; network.connect("localhost", 65000); network.startNetwork(); ... //initialize serializers } public void setMyVehicle(VehicleRender myVehicle) { network.send(0, METHODS.createVehicle, new NetworkCommand( NetworkCommand.CREATE)); } public void removeVehicle(VehicleRender myVehicle) { this.myVehicle = myVehicle; } public void setMyVehicle(VehicleRender //Component - SOP public class Game { public void run() { } .... vehicle) { vehicles.remove(vehicle); renderer.removeDrawable(vehicle); public void removeVehicle(VehicleRender vehicle) { if (vehicle.getModel().getOid() == getMyVehicle().getModel().getOid()) { network.send(0, METHODS.deleteVehicle, vehicle.getModel()); } } Código Componente VehicleModel public class VehicleModel { public void move(int x, int y) { this.position.move(x, y); } //Component - SOP public class VehicleModel { public void move(int x, int y) { ClientNetwork network = ClientNetwork.instance; } network.send(0, METHODS.updatePosition, this); } } Código Componente GameServer public class VehicleGameServer { public void addVehicle(VehicleModel vehicle, int connectionOwner){ clientsMap.put(connectionOwner, vehicle); for (Entry<Integer, VehicleModel> entry: clientsMap.entrySet()) { Integer connectionId = entry.getKey(); if (!connectionId.equals(connectionOwner)){ //Component - SOP public class VehicleGameServer { void vehicleAdded(VehicleModel vehicle, Integer connectionId) { network.send(connectionId, 0, METHODS.vehicleAdded, vehicle); } vehicleAdded(vehicle, connectionId); vehicleAdded(entry.getValue(), connectionOwner); } } network.send(connectionId, 0, METHODS.vehicleDeleted, vehicle); } void vehicleRemoved(VehicleModel vehicle, Integer connectionId) { void vehicleAdded(VehicleModel vehicle, Integer connectionId) { // not implemente here } } Código Componente GameServer (cont.) public void removeVehicle(VehicleModel vehicle, int connectionOwner) { clientsMap.remove(connectionOwner); for (Entry<Integer, VehicleModel> entry: clientsMap.entrySet()) { vehicleRemoved(vehicle, public void run() { try { network.startServer(65000); entry.getKey()); } } void vehicleRemoved(VehicleModel vehicle, Integer key) { // not implemente here } public void run() { System.out.println("running"); } } catch (IOException e) { } ..... } throw new RuntimeException(e); } ..... //other initialization related with network } Dificuldades Encontradas Novo paradigma de programação Ferramenta HyperJ sem código aberto (apenas os bytecodes) Algumas limitações da ferramenta HyperJ como, geração automática de construtor (protegidos) que não fazem parte da aplicação, problemas de acesso a atributos Java (AlgumaClasse.class), Enums, Innerclasses Demonstração da Aplicação Conclusões Apesar das limitações da ferramenta HyperJ foi possível realizar o trabalho com sucesso, aplicando esse novo paradigma de programação HyperJ, atualmente é a única implementação que suporta SOP em Java Uma API bem definida torna fácil a evolução e manutenção de aplicativos que usam SOP Perguntas?