Привет! Я делаю свое приложение настольной игры на vue.js
У меня есть функции инициализации ролей, но есть проблема в том, что инициализация проходит несколько раз. Помоги сделать так, чтобы инициализация происходила единожды
server.js
const { RESOURCES, initResources } = require('./data/resources.js');
const WebSocket = require('ws');
const os = require('os');

function broadcast(data) {
  wss.clients.forEach(client => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(JSON.stringify(data));
    }
  });
}

function getLocalIp() {
  const interfaces = os.networkInterfaces();
  for (const name of Object.keys(interfaces)) {
    for (const net of interfaces[name]) {
      // Пропускаем внутренние и не-IPv4 интерфейсы
      if (net.family === 'IPv4' && !net.internal) {
        return net.address;
      }
    }
  }
  return 'localhost'; // Fallback
}
const LOCAL_IP = getLocalIp();
const WS_PORT = 8080;

const wss = new WebSocket.Server({ host: '0.0.0.0', port: WS_PORT });

const roles = ['lady', 'sir', 'captain', 'fmate', 'frenchy', 'kid'];

let player = {
  nickname: '',
  role: '',
  friend: '',
  foe: '',
}

let gameState = {
  isGameStarted: false,
  round: 0,
  phase: 'init',
  players: [],
  resources: initResources,
  threats: [],
  turn: {
    currentPlayerId: 0,
    phase: ''
  },
  gameStatus: ''
}

const games = new Map();
wss.on('connection', (ws) => {
  ws.player = player;
  ws.isPlaying = false;

  ws.send(JSON.stringify({
    type: 'FULL_STATE_UPDATE',
    state: gameState,
  }))

  function broadcastPlayerStats() {
    const playerCount = Array.from(wss.clients).filter(
      client => client.isPlaying && client.readyState === WebSocket.OPEN
    ).length;
    const totalCount = Array.from(wss.clients).filter(
      client => client.readyState === WebSocket.OPEN
    ).length;

    broadcast({
      command: 'player_stats',
      playerCount,
      totalCount,
    });
  }

  function broadcastState() {
    broadcast({
      type: 'FULL_STATE_UPDATE',
      state: gameState
    });
  }

  function onPlay() {
    if (!ws.isPlaying) {
      ws.isPlaying = true;
      broadcastPlayerStats();

      console.log(`Player ready. Ready players: ${Array.from(wss.clients).filter(
        client => client.isPlaying && client.readyState === WebSocket.OPEN
      ).length}`);

      //gameState.players.push(ws.player);
    }
  }

  function onChatMessage(msg) {
    broadcast({
      command: 'chat_message',
      text: msg.text,
      nickname: msg.nickname,
    });
  }

  function onInitRoles() {
    const players = Array.from(wss.clients).filter(client =>
      client.isPlaying && client.readyState === WebSocket.OPEN
    );

    if (players.length > roles.length) {
      ws.send(JSON.stringify({ error: 'Not enough roles for all players' }));
      return;
    }

    const shuffledRoles = [...roles].sort(() => Math.random() - 0.5).slice(players.length);
    const foeRoles = [...shuffledRoles].sort(() => Math.random() - 0.5);//.slice(players.length);
    const friendRoles = [...shuffledRoles].sort(() => Math.random() - 0.5);//.slice(players.length);
    console.log(`shuffledRoles: ${shuffledRoles}`);
    console.log(`foeRoles: ${foeRoles}`);
    console.log(`friendRoles: ${friendRoles}`);


    gameState.players = players.map((client, index) => ({
      role: shuffledRoles[index],
      foe: foeRoles[index],
      friend: friendRoles[index],
      id: index
    }));

    broadcastState();


    /// Sending index to every user
    Array.from(wss.clients).forEach((client, index) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(JSON.stringify({command:'get_id', id: index}));
      }
    });
    return { success: true };
  }

  // function onGameIsStarted() {
  //   gameState.gameStatus = true;

  //   broadcast(JSON.stringify({command: 'game_is_started', gameState}))
  // }

  function startGame() {
    gameState.isGameStarted = true;
    gameState.gameStatus = 'playing';
    broadcastState();
  }

  ws.on('message', (message) => {
    let msg;
    try {
      msg = JSON.parse(message);
    } catch (e) {
      ws.send(JSON.stringify({ error: 'Invalid message format, must be JSON' }));
      return;
    }

    switch (msg.command) {
      case 'play':
        onPlay();
        break;

      case 'init_roles':
        onInitRoles();
        break;

      case 'start_game':
        startGame();
        break;

      case 'chat_message':
        onChatMessage(msg);
        break;

      default:
        ws.send(JSON.stringify({ error: 'Unknown command' }));
    }
  });

  ws.on('close', () => {
    if (ws.isPlaying) {
      ws.isPlaying = false;
      broadcastPlayerStats();

      console.log(`Player left. Ready players: ${Array.from(wss.clients).filter(
        client => client.isPlaying && client.readyState === WebSocket.OPEN
      ).length}`);
    }
  });
});

console.log(`WebSocket server is running on:
  Local: ws://localhost:${WS_PORT}
  Network: ws://${LOCAL_IP}:${WS_PORT}`);

gameModule.js
//import { CHARACTERS } from '@/store/data/characters'
//import { RESOURCES } from '@/store/data/resources'

//const phase = { dealing: 'dealing', action: 'action', threatResolution: 'threat_resolution'}

export const gameModule = {
    namespaced: true,
    state: () => ({
        ws: null,
        id: null,
        isConnected: false,
        isGameStarted: false,
        round: 0,
        phase: 'init',
        players: [],
        resources: [],
        threats: [],
        turn: {
            currentPlayerId: 0,
            phase: ''
        },
        gameStatus: '',
        playerStats: {
            playerCount: 0,
            totalCount: 0,
        }
    }),
    getters: {
        currentPlayer: state => state.players[state.turn.currentPlayerId],
        isGameStarted: state => state.isGameStarted,
        playerRole: (state, getters, rootState) =>
            state.players.find(p => p.id === rootState.user.id)?.role || null,
    },
    mutations: {
        SET_WS(state, ws) {
            state.ws = ws;
        },
        SET_ID(state, id) {
            state.id = id;
        },
        SET_CONNECTION(state, status) {
            state.isConnected = status;
        },
        UPDATE_STATE(state, newState) {
            Object.assign(state, newState);
        },
        SET_PLAYER_STATS(state, stats) {
            state.playerStats = stats;
        },
        START_GAME(state) {
            state.isGameStarted = true;
        },
        SET_PLAYERS(state, newPlayers) {
            state.players = newPlayers;
        },
        SET_PHASE(state, phase) {
            state.phase = phase;
        },
        NEXT_ROUND(state) {
            state.round++;
        },
        // SET_ROLE_FOR_PLAYER(state, { playerId, role }) {},
        // DRAW_CARD(state, playerId) {},
        // MOVE_PLAYER(state, { playerId, location }) {},
        // PICK_ITEM(state, { playerId, item }) {},
        // USE_ITEM(state, { playerId, item }) {},
        // APPLY_THREAT(state, { location, threat }) {},
        // RESOLVE_THREAT(state, { location, threat }) {},
        // CHANGE_HEALTH(state, { playerId, amount }) {},
        // NEXT_TURN(state) {},
        // SET_GAME_STATUS(state, status) {},
    },
    actions: {
        connect({ commit }) {
            const ws = new WebSocket('ws://26.161.24.213:8080');
            commit('SET_WS', ws);

            ws.addEventListener('open', () => {
                commit('SET_CONNECTION', true);
            });

            ws.addEventListener('message', (event) => {
                const data = JSON.parse(event.data);

                switch (data.type || data.command) {
                    case 'FULL_STATE_UPDATE':
                        commit('UPDATE_STATE', data.state);
                        break;

                    case 'player_stats':
                        commit('SET_PLAYER_STATS', {
                            playerCount: data.playerCount,
                            totalCount: data.totalCount
                        });
                        break;

                    case 'get_id':
                        commit('SET_ID', data.id);
                        break;

                }
            });

            ws.addEventListener('close', () => {
                commit('SET_CONNECTION', false);
            })
        },
        
        play({ state }) {
            if(state.ws) {
                state.ws.send(JSON.stringify({ command: 'play'}))
            }
        },

        initRoles({ state }) {
            if (state.ws) {
                state.ws.send(JSON.stringify({ command: 'init_roles'}));
            }
        },

        startGame({ state }) {
            if (state.ws) {
                state.ws.send(JSON.stringify({ command: 'start_game'}));
            }
        },
        // playerTurn({commit, state}) {},
        // movePlayer({ commit, state }, { playerId, targetLocation }) {},
        // playerAction({ commit, state }, { playerId, action }) {},
        // resolveThreats({ commit, state }) {},
        // endGame({ commit, state }) {},
    }
}

GamePage.vue
<template>
    <div class="game__wrapper">
        <ChatComponent :ws="ws"/>
        <div class="game__block">
            <div v-if="isGameStarted">
                <GameBoard :ws="ws"/>
            </div>
            <div v-else class="play__block">
                <menu-button @click="play" :disabled="isPlaying">
                    {{ isPlaying ? 'Waiting for others...' : 'Play'}}
                </menu-button>
                <p>
                    {{ playerStats.playerCount }} out of {{ playerStats.totalCount }} players want to play
                </p>
            </div>
        </div>
    </div>
</template>

<script>
import { mapState, mapActions } from 'vuex'
//import СhatComponent from '@renderer/components/СhatComponent.vue';
import ChatComponent from '@/components/СhatComponent.vue';
import GameBoard from '@/components/GameBoard.vue';

export default {
    components: {
        ChatComponent,
        GameBoard,
    },
    computed: {
        ...mapState('game', [
            'ws',
            'isGameStarted',
            'playerStats',
            'isConnected',
        ]),
        isPlaying() {
            //return this.playerStats.playerCount > 0;
            return this.ws.isPlaying;
        }
    },  
    created() {
        this.connect();
    },
    methods: {
        ...mapActions('game', [
            'connect',
            'play',
            'initRoles',
            'startGame',
        ]),


        checkAllready() {
            if (this.playerStats.playerCount === this.playerStats.totalCount &&
                this.playerStats.totalCount > 0) {
                    console.log('hohol')
                    this.initRoles();
                    this.$nextTick(() => {
                        this.startGame();
                    })
                }
        }
    },
    watch: {
        //'playerStats.playerCount': 'checkAllReady'
        'playerStats.playerCount'() { this.checkAllready() },
    },
}
</script>