Class: LZRTag::Handler::Game

Inherits:
Count show all
Defined in:
lib/lzrtag/handler/game_handler.rb

Overview

Game handler class, managing game registration and game ticks. This class manages the lifecycle of any lasertag game started in it. This includes sending a gameTick, managing phase and game state transitions, sending out but also receiving information on the game state via MQTT, etc.

Examples:

handler = LZRTag::Handler::Game.new(mqtt);

handler.register_game("My Game", SomeGame);
handler.register_game("Other game!", SomeOtherGame);

handler.start_game(SomeGame); # This will fetch the registered name and publish to MQTT
                    # Alternatively, sending to Lasertag/Game/Controls/SetGame with
                    # the string name will switch to the game.

# Game and phase switching is possible at any time, and will be handled asynchronously
sleep 5;
handler.set_phase(:somePhase);

Instance Attribute Summary collapse

Attributes inherited from Count

#brightnessCount, #teamCount

Attributes inherited from Base

#idTable, #mqtt

Instance Method Summary collapse

Methods inherited from HitArb

#_handle_hitArb, #process_raw_hit

Methods inherited from Base

#[], #add_hook, #each, #num_connected, #remove_hook, #send_event

Constructor Details

#initialize(*data, **argHash) ⇒ Game

Returns a new instance of Game.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/lzrtag/handler/game_handler.rb', line 45

def initialize(*data, **argHash)
  super(*data, **argHash)

  @lastTick = Time.now();

  @lastGame    = nil;
  @currentGame = nil;
  @nextGame   = nil;

  @gamePhase = :idle;

  @gamePlayers = Array.new();

  @knownGames = Hash.new();

  _start_game_thread();

  @mqtt.subscribe_to "Lasertag/Game/Controls/+" do |data, topics|
    case topics[0]
    when "SetPhase"
      phase = data.to_sym;
      if(get_allowed_phases().include? phase)
        set_phase(phase);
      end
    when "SetGame"
      if(@knownGames[data])
        start_game(@knownGames[data])
      elsif(data == "STOP")
        stop_game();
      end
    end
  end

  clean_game_topics();
  at_exit {
    clean_game_topics();
  }
end

Instance Attribute Details

#currentGameObject (readonly)

Returns the instance of the currently active game, or nil if none is present



28
29
30
# File 'lib/lzrtag/handler/game_handler.rb', line 28

def currentGame
  @currentGame
end

#gamePhaseObject

currently active game phase When set it will start a phase change, sending :gamePhaseEnds and :gamePhaseStarts events

Returns:

  • Symbol

See Also:



35
36
37
# File 'lib/lzrtag/handler/game_handler.rb', line 35

def gamePhase
  @gamePhase
end

#gamePlayersObject

List of in-game players. This list is mainly to keep track of which players the game is acting upon, but updating it will also send a list of player ID Strings to MQTT (Lasertag/Game/ParticipatingPlayers), and will send :playerEnteredGame and :playerLeftGame events



43
44
45
# File 'lib/lzrtag/handler/game_handler.rb', line 43

def gamePlayers
  @gamePlayers
end

Instance Method Details

#consume_event(event, data) ⇒ Object



135
136
137
138
139
140
# File 'lib/lzrtag/handler/game_handler.rb', line 135

def consume_event(event, data)
  super(event, data)

  return unless @currentGame
  @currentGame.consume_event(event, data);
end

#each_participatingObject

Yield for each currently in-game player



246
247
248
249
250
# File 'lib/lzrtag/handler/game_handler.rb', line 246

def each_participating()
  @gamePlayers.each do |pl|
    yield(pl)
  end
end

#get_allowed_phasesObject

Returns an Array<Symbol> of the currently allowed phases of this game. This list can also be retrieved via MQTT, under Lasertag/Game/CurrentGame



184
185
186
187
188
189
190
191
# File 'lib/lzrtag/handler/game_handler.rb', line 184

def get_allowed_phases()
  allowedPhases = [:idle]
  if(@currentGame)
    allowedPhases = [allowedPhases, @currentGame.phases].flatten
  end

  return allowedPhases;
end

#in_game?(player) ⇒ Boolean

Check if a player is currently in game

Returns:

  • (Boolean)


253
254
255
# File 'lib/lzrtag/handler/game_handler.rb', line 253

def in_game?(player)
  return @gamePlayers.include? player
end

#register_game(gameTag, game) ⇒ Object

Register a game by a tag. This function will register a given LZRTag::Game::Base class under a given string tag. This tag can then be used to, via MQTT, start the game, and is also used to give players a cleartext game name. A list of games is published to Lasertag/Game/KnownGames

Parameters:

  • gameTag (String)

    Cleartext name of the game

  • game (LZRTag::Game::Base)

    The game class to register

Raises:

  • (ArgumentError)


125
126
127
128
129
130
131
132
# File 'lib/lzrtag/handler/game_handler.rb', line 125

def register_game(gameTag, game)
  raise ArgumentError, "Game Tag must be a string!" unless gameTag.is_a? String
  raise ArgumentError, "Game must be a LZRTag::Game class" unless game <= LZRTag::Game::Base

  @knownGames[gameTag] = game;

  @mqtt.publish_to "Lasertag/Game/KnownGames", @knownGames.keys.to_json, retain: true;
end

#set_phase(nextPhase) ⇒ Object

Tries to change the current phase. This function will set the current phase to nextPhase, if it is an allowed one. However, if nextPhase does not belong to the list of allowed phases, and error is raised. The :gamePhaseEnds and :gamePhaseStarts events are triggered properly. This function can be called from any context, not just inside the game code itself.

Raises:

  • (ArgumentError)

See Also:



200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/lzrtag/handler/game_handler.rb', line 200

def set_phase(nextPhase)
  allowedPhases = get_allowed_phases();

  raise ArgumentError, "Phase must be valid!" unless allowedPhases.include? nextPhase

  puts "Phase started: #{nextPhase}!".green;

  oldPhase = @gamePhase
  send_event(:gamePhaseEnds, oldPhase, nextPhase)

  @mqtt.publish_to "Lasertag/Game/Phase/Current", @gamePhase.to_s, retain: true
  @gamePhase = nextPhase;
  send_event(:gamePhaseStarts, nextPhase, oldPhase);
end

#start_game(game = @lastGame) ⇒ Object

Starts a given new game (or the last one). This function will take either a String (as registered with register_game), or a LZRTag::Game::Base class, instantiate it, and start it. If no fitting game was found, the game is instead stopped.

Parameters:

  • game (String, LZRTag::Game::Base) (defaults to: @lastGame)

    The game, or game name, to start



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/lzrtag/handler/game_handler.rb', line 147

def start_game(game = @lastGame)
  @lastGame = game;

  if(game.is_a? String and gClass = @knownGames[game])
    game = gClass;
  elsif(game.is_a? String)
    stop_game();
    return;
  end

  if(gKey = @knownGames.key(game))
    @mqtt.publish_to "Lasertag/Game/CurrentGame", gKey, retain: true
    puts "Starting game #{gKey}!".green
  else
    @mqtt.publish_to "Lasertag/Game/CurrentGame", "", retain: true
  end

  game = game.new(self) if game.is_a? Class and game <= LZRTag::Game::Base;
  unless(game.is_a? LZRTag::Game::Base)
    raise ArgumentError, "Game class needs to be specified!"
  end
  @nextGame = game;
  send_event(:gameStarting, @nextGame);

  @gameTickThread.run();
  @mqtt.publish_to "Lasertag/Game/Phase/Valid",
    get_allowed_phases.to_json(), retain: true
end

#stop_gameObject

Stops the currently running game.



177
178
179
180
# File 'lib/lzrtag/handler/game_handler.rb', line 177

def stop_game()
  @nextGame = nil;
  @mqtt.publish_to "Lasertag/Game/CurrentGame", "", retain: true
end