jemini 2009.10.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.txt +9 -0
- data/bin/jemini +26 -0
- data/lib/ibxm.jar +0 -0
- data/lib/jinput.jar +0 -0
- data/lib/jogg-0.0.7.jar +0 -0
- data/lib/jorbis-0.0.15.jar +0 -0
- data/lib/jruby-complete.jar +0 -0
- data/lib/lwjgl.jar +0 -0
- data/lib/lwjgl_util_applet.jar +0 -0
- data/lib/native_files/OpenAL32.dll +0 -0
- data/lib/native_files/jinput-dx8.dll +0 -0
- data/lib/native_files/jinput-dx8_64.dll +0 -0
- data/lib/native_files/jinput-raw.dll +0 -0
- data/lib/native_files/jinput-raw_64.dll +0 -0
- data/lib/native_files/jinput-wintab.dll +0 -0
- data/lib/native_files/libjinput-linux.so +0 -0
- data/lib/native_files/libjinput-linux64.so +0 -0
- data/lib/native_files/libjinput-osx.jnilib +0 -0
- data/lib/native_files/liblwjgl.jnilib +0 -0
- data/lib/native_files/liblwjgl.so +0 -0
- data/lib/native_files/liblwjgl64.so +0 -0
- data/lib/native_files/libopenal.so +0 -0
- data/lib/native_files/lwjgl.dll +0 -0
- data/lib/native_files/openal.dylib +0 -0
- data/lib/natives-linux.jar +0 -0
- data/lib/natives-mac.jar +0 -0
- data/lib/natives-win32.jar +0 -0
- data/lib/phys2d.jar +0 -0
- data/lib/slick.jar +0 -0
- data/package/jar/jemini.jar +0 -0
- data/src/behavior.rb +248 -0
- data/src/behavior_event.rb +23 -0
- data/src/behaviors/animated_image.rb +88 -0
- data/src/behaviors/audible.rb +16 -0
- data/src/behaviors/axis_stateful.rb +35 -0
- data/src/behaviors/bounding_box_collidable.rb +27 -0
- data/src/behaviors/cardinal_movable.rb +121 -0
- data/src/behaviors/clickable.rb +19 -0
- data/src/behaviors/countable.rb +32 -0
- data/src/behaviors/debug_physical.rb +43 -0
- data/src/behaviors/debug_tangible.rb +31 -0
- data/src/behaviors/drawable.rb +7 -0
- data/src/behaviors/drawable_image.rb +111 -0
- data/src/behaviors/drawable_line.rb +32 -0
- data/src/behaviors/drawable_shape.rb +48 -0
- data/src/behaviors/fading_image_trail_emittable.rb +32 -0
- data/src/behaviors/game_object_emittable.rb +13 -0
- data/src/behaviors/grid_bound.rb +108 -0
- data/src/behaviors/handles_events.rb +33 -0
- data/src/behaviors/inertial.rb +14 -0
- data/src/behaviors/magnetic.rb +34 -0
- data/src/behaviors/metered.rb +3 -0
- data/src/behaviors/movable.rb +81 -0
- data/src/behaviors/particle_emitter.rb +27 -0
- data/src/behaviors/physical.rb +384 -0
- data/src/behaviors/physical_cardinal_movable.rb +111 -0
- data/src/behaviors/physical_image.rb +45 -0
- data/src/behaviors/pointer.rb +30 -0
- data/src/behaviors/pressable.rb +17 -0
- data/src/behaviors/regional.rb +76 -0
- data/src/behaviors/rotates_to_point.rb +19 -0
- data/src/behaviors/spatial.rb +43 -0
- data/src/behaviors/stateful.rb +33 -0
- data/src/behaviors/taggable.rb +28 -0
- data/src/behaviors/tangible.rb +59 -0
- data/src/behaviors/timeable.rb +88 -0
- data/src/behaviors/top_down_vehicle.rb +42 -0
- data/src/behaviors/triangle_trail_emittable.rb +46 -0
- data/src/behaviors/unique.rb +0 -0
- data/src/behaviors/updates.rb +8 -0
- data/src/behaviors/updates_at_consistant_rate.rb +28 -0
- data/src/behaviors/vectored_movement.rb +48 -0
- data/src/behaviors/world_collidable.rb +9 -0
- data/src/color.rb +70 -0
- data/src/events/grid_changed_event.rb +8 -0
- data/src/events/physical_message.rb +9 -0
- data/src/events/tangible_collision_event.rb +8 -0
- data/src/file_system.rb +17 -0
- data/src/game.rb +110 -0
- data/src/game_object.rb +176 -0
- data/src/game_objects/background.rb +10 -0
- data/src/game_objects/fading_image.rb +23 -0
- data/src/game_objects/tangible_object.rb +4 -0
- data/src/game_objects/text.rb +71 -0
- data/src/game_objects/triangle_trail.rb +85 -0
- data/src/game_state.rb +164 -0
- data/src/inflector.rb +68 -0
- data/src/input_helpers/joystick_dead_zone_filter.rb +9 -0
- data/src/jemini.rb +31 -0
- data/src/jemini_version.rb +4 -0
- data/src/listenable_mixin.rb +15 -0
- data/src/logger_mixin.rb +11 -0
- data/src/managers/basic_game_object_manager.rb +95 -0
- data/src/managers/basic_physics_manager.rb +95 -0
- data/src/managers/basic_render_manager.rb +49 -0
- data/src/managers/basic_tile_manager.rb +3 -0
- data/src/managers/basic_update_manager.rb +30 -0
- data/src/managers/diagnostic/diagnostic_input_manager.rb +0 -0
- data/src/managers/input_manager.rb +161 -0
- data/src/managers/input_support/input_binding.rb +77 -0
- data/src/managers/input_support/input_builder.rb +44 -0
- data/src/managers/input_support/input_listener.rb +74 -0
- data/src/managers/input_support/input_message.rb +5 -0
- data/src/managers/input_support/joystick_listener.rb +53 -0
- data/src/managers/input_support/key_listener.rb +27 -0
- data/src/managers/input_support/mouse_listener.rb +38 -0
- data/src/managers/input_support/slick_input_listener.rb +20 -0
- data/src/managers/input_support/slick_input_message.rb +11 -0
- data/src/managers/input_support/slick_input_translator.rb +15 -0
- data/src/managers/message_queue.rb +60 -0
- data/src/managers/network_manager.rb +41 -0
- data/src/managers/render_support/hardware_cursor.rb +13 -0
- data/src/managers/resource_manager.rb +167 -0
- data/src/managers/sound_manager.rb +47 -0
- data/src/managers/tag_manager.rb +47 -0
- data/src/managers/tangible_manager.rb +36 -0
- data/src/math.rb +23 -0
- data/src/org/rubyforge/rawr/Main.java +67 -0
- data/src/platform.rb +28 -0
- data/src/proc_enhancement.rb +5 -0
- data/src/project_generator.rb +138 -0
- data/src/resource.rb +31 -0
- data/src/spline.rb +13 -0
- data/src/states/input_diagnostic_state.rb +53 -0
- data/src/vector.rb +143 -0
- data/test/test_state.rb +3 -0
- metadata +188 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'managers/input_support/input_listener'
|
|
2
|
+
|
|
3
|
+
module Jemini
|
|
4
|
+
class InputBinding
|
|
5
|
+
MOUSE_BUTTON_NAMES = [:mouse_left, :mouse_right, :mouse_middle].freeze
|
|
6
|
+
attr_reader :action_name, :listeners
|
|
7
|
+
|
|
8
|
+
def initialize(action_name)
|
|
9
|
+
@action_name = action_name
|
|
10
|
+
@listeners = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# type can be one of :hold, :release, :press, and :move
|
|
14
|
+
def add_input_listener(type, button_id, options={})
|
|
15
|
+
device = detect_device(button_id, type)
|
|
16
|
+
real_button = detect_button(button_id, device)
|
|
17
|
+
value = options[:value]
|
|
18
|
+
to = options[:to]
|
|
19
|
+
listener = InputListener.create(action_name, type, device, real_button)
|
|
20
|
+
listener.default_value = value
|
|
21
|
+
listener.message_to = to
|
|
22
|
+
InputManager.loading_input_manager.listeners << listener
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def detect_device(button_id, type)
|
|
26
|
+
if mouse_button?(button_id, type)
|
|
27
|
+
:mouse
|
|
28
|
+
else
|
|
29
|
+
:key
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def detect_button(button_id, device)
|
|
34
|
+
case device
|
|
35
|
+
when :mouse
|
|
36
|
+
detect_mouse_button(button_id)
|
|
37
|
+
when :key
|
|
38
|
+
case button_id.to_s
|
|
39
|
+
when /(left|right)_alt/
|
|
40
|
+
"Input::KEY_#{$1[0].chr.upcase}ALT".constantize
|
|
41
|
+
when /(left|right)_ctrl/
|
|
42
|
+
"Input::KEY_#{$1[0].chr.upcase}CONTROL".constantize
|
|
43
|
+
when /(left|right)_bracket/
|
|
44
|
+
"Input::KEY_#{$1[0].chr.upcase}BRACKET".constantize
|
|
45
|
+
when /(up|down|left|right)_arrow/
|
|
46
|
+
"Input::KEY_#{$1.upcase}".constantize
|
|
47
|
+
when /(left|right)_shift/
|
|
48
|
+
"Input::KEY_#{$1[0].chr.upcase}SHIFT".constantize
|
|
49
|
+
else
|
|
50
|
+
"Input::KEY_#{button_id.to_s.underscore.upcase}".constantize
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def mouse_button?(button_id, type)
|
|
56
|
+
return true if type == :move && button_id == :mouse
|
|
57
|
+
return true if MOUSE_BUTTON_NAMES.include? button_id
|
|
58
|
+
return false unless button_id.respond_to? :has_key?
|
|
59
|
+
return true if button_id.has_key? :mouse_button
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def detect_mouse_button(button_id)
|
|
63
|
+
case button_id
|
|
64
|
+
when :mouse_left
|
|
65
|
+
0
|
|
66
|
+
when :mouse_right
|
|
67
|
+
1
|
|
68
|
+
when :mouse_middle
|
|
69
|
+
2
|
|
70
|
+
when :mouse
|
|
71
|
+
nil
|
|
72
|
+
else
|
|
73
|
+
button_id[:mouse_button]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'managers/input_support/input_binding'
|
|
2
|
+
require 'logger_mixin'
|
|
3
|
+
|
|
4
|
+
module Jemini
|
|
5
|
+
class InputBuilder
|
|
6
|
+
|
|
7
|
+
include LoggerMixin
|
|
8
|
+
|
|
9
|
+
def self.declare
|
|
10
|
+
yield new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def in_order_to(action_name)
|
|
14
|
+
log.debug "in_order_to: #{action_name}"
|
|
15
|
+
@current_binding = create_binding(action_name)
|
|
16
|
+
yield self
|
|
17
|
+
@current_binding = nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def create_binding(action_name)
|
|
21
|
+
InputBinding.new(action_name)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def hold(button, options={})
|
|
25
|
+
log.debug "hold: #{button}, #{options}"
|
|
26
|
+
@current_binding.add_input_listener(:hold, button, options)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def press(button, options={})
|
|
30
|
+
log.debug "press: #{button}, #{options}"
|
|
31
|
+
@current_binding.add_input_listener(:press, button, options)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def release(button, options={})
|
|
35
|
+
log.debug "release: #{button}, #{options}"
|
|
36
|
+
@current_binding.add_input_listener(:release, button, options)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def move(button, options={})
|
|
40
|
+
log.debug "move: #{button}, #{options}"
|
|
41
|
+
@current_binding.add_input_listener(:move, button, options)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'managers/input_support/input_message'
|
|
2
|
+
|
|
3
|
+
module Jemini
|
|
4
|
+
class InputListener
|
|
5
|
+
attr_accessor :device,
|
|
6
|
+
:input_type,
|
|
7
|
+
:input_button_or_axis,
|
|
8
|
+
:joystick_id,
|
|
9
|
+
:destination_type,
|
|
10
|
+
:destination_value,
|
|
11
|
+
:input_callback,
|
|
12
|
+
:game_state,
|
|
13
|
+
:default_value,
|
|
14
|
+
:message_to
|
|
15
|
+
|
|
16
|
+
def self.create(message, type, device, button_id, options={}, &callback)
|
|
17
|
+
options[:input_callback] = callback
|
|
18
|
+
device_type = case device
|
|
19
|
+
when :key
|
|
20
|
+
KeyListener
|
|
21
|
+
when :mouse
|
|
22
|
+
MouseListener
|
|
23
|
+
when :joystick
|
|
24
|
+
JoystickListener
|
|
25
|
+
end
|
|
26
|
+
device_type.new(message, type, button_id, options)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# TODO: Indicate whether or not a joystick mapping is active if a joystick is not installed
|
|
30
|
+
def initialize(message, button_type, button_id, options)
|
|
31
|
+
@input_type = button_type
|
|
32
|
+
@input_button_or_axis = button_id
|
|
33
|
+
@game_message = message
|
|
34
|
+
# TODO: There has to be a better, threadsafe way to do this.
|
|
35
|
+
# Maybe threadsafety isn't a huge concern here?
|
|
36
|
+
@game_state = Jemini::InputManager::loading_input_manager.game_state
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def poll(raw_input)
|
|
40
|
+
@poll_result = poll_value(raw_input)
|
|
41
|
+
if post_canceled?
|
|
42
|
+
@cancel_post = false
|
|
43
|
+
nil
|
|
44
|
+
else
|
|
45
|
+
to_game_message(raw_input, @poll_result)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def cancel_post!
|
|
50
|
+
@cancel_post = true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def post_canceled?
|
|
54
|
+
@cancel_post
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def key
|
|
58
|
+
"#{@device}_#{@input_type}_#{@input_button_or_axis}_#{@joystick_id || 'any'}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def to_s
|
|
62
|
+
key
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# eventually, raw_input will need to be wrapped
|
|
66
|
+
def to_game_message(raw_input, game_value)
|
|
67
|
+
game_message = InputMessage.new(@game_message, default_value || game_value)
|
|
68
|
+
game_message.player = @player
|
|
69
|
+
@input_callback.call(game_message, raw_input) unless @input_callback.nil?
|
|
70
|
+
game_message.to = message_to
|
|
71
|
+
game_message
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'managers/input_support/input_listener'
|
|
2
|
+
|
|
3
|
+
module Jemini
|
|
4
|
+
class JoystickListener < Jemini::InputListener
|
|
5
|
+
def device
|
|
6
|
+
:joystick
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def find_axis_id_by_axis_name(raw_input, axis_name)
|
|
10
|
+
(0..raw_input.get_axis_count(@joystick_id)).find {|axis_id| raw_input.get_axis_name(@joystick_id, axis_id) == axis_name}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def poll_value(raw_input)
|
|
14
|
+
if @joystick_id && @joystick_id >= raw_input.controller_count
|
|
15
|
+
cancel_post!
|
|
16
|
+
return
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
case @input_type
|
|
20
|
+
when :axis_update
|
|
21
|
+
@axis_id ||= find_axis_id_by_axis_name(raw_input, @input_button_or_axis)
|
|
22
|
+
axis_value = raw_input.get_axis_value(@joystick_id, @axis_id)
|
|
23
|
+
axis_value
|
|
24
|
+
when :pressed
|
|
25
|
+
if @joystick_id.nil?
|
|
26
|
+
result = (0..raw_input.controller_count).any? {|i| raw_input.is_button_pressed(@input_button_or_axis, i)} unless raw_input.controller_count.zero?
|
|
27
|
+
else
|
|
28
|
+
result = raw_input.is_button_pressed(@input_button_or_axis, @joystick_id)
|
|
29
|
+
end
|
|
30
|
+
pressed = !@key_down_on_last_poll && result
|
|
31
|
+
@key_down_on_last_poll = result
|
|
32
|
+
cancel_post! unless pressed
|
|
33
|
+
pressed
|
|
34
|
+
when :held
|
|
35
|
+
if @joystick_id.nil?
|
|
36
|
+
result = (0..raw_input.controller_count).any? {|i| raw_input.is_button_pressed(@input_button_or_axis, i)} unless raw_input.controller_count.zero?
|
|
37
|
+
else
|
|
38
|
+
result = raw_input.is_button_pressed(@input_button_or_axis, @joystick_id)
|
|
39
|
+
end
|
|
40
|
+
cancel_post! unless result
|
|
41
|
+
result
|
|
42
|
+
when :released
|
|
43
|
+
button_down = raw_input.is_button_pressed(@input_button_or_axis, @joystick_id)
|
|
44
|
+
result = (@key_down_on_last_poll && !button_down) ? true : false
|
|
45
|
+
@key_down_on_last_poll = button_down
|
|
46
|
+
cancel_post! unless result
|
|
47
|
+
result
|
|
48
|
+
else
|
|
49
|
+
cancel_post!
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'managers/input_support/input_listener'
|
|
2
|
+
|
|
3
|
+
module Jemini
|
|
4
|
+
class KeyListener < Jemini::InputListener
|
|
5
|
+
def device
|
|
6
|
+
:key
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def poll_value(raw_input)
|
|
10
|
+
case @input_type
|
|
11
|
+
when :press
|
|
12
|
+
cancel_post! unless raw_input.is_key_pressed(@input_button_or_axis)
|
|
13
|
+
when :hold
|
|
14
|
+
cancel_post! unless raw_input.is_key_down(@input_button_or_axis)
|
|
15
|
+
when :release
|
|
16
|
+
key_down = raw_input.is_key_down(@input_button_or_axis)
|
|
17
|
+
result = (@key_down_on_last_poll && !key_down) ? true : false
|
|
18
|
+
@key_down_on_last_poll = key_down
|
|
19
|
+
cancel_post! unless result
|
|
20
|
+
else
|
|
21
|
+
cancel_post!
|
|
22
|
+
raise "Input type of #{@input_type.inspect} is not supported!"
|
|
23
|
+
end
|
|
24
|
+
@game_value unless post_canceled?
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'managers/input_support/input_listener'
|
|
2
|
+
|
|
3
|
+
module Jemini
|
|
4
|
+
class MouseListener < Jemini::InputListener
|
|
5
|
+
def device
|
|
6
|
+
:mouse
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def poll_value(raw_input)
|
|
10
|
+
value = MouseValue.new
|
|
11
|
+
value.position = percent_on_screen(raw_input)
|
|
12
|
+
value.screen_position = Vector.new(raw_input.mouse_x, raw_input.mouse_y)
|
|
13
|
+
case @input_type
|
|
14
|
+
when :move, :axis_update
|
|
15
|
+
|
|
16
|
+
when :press
|
|
17
|
+
cancel_post! unless raw_input.mouse_pressed?(@input_button_or_axis)
|
|
18
|
+
when :hold
|
|
19
|
+
cancel_post! unless raw_input.mouse_button_down?(@input_button_or_axis)
|
|
20
|
+
when :release
|
|
21
|
+
button_down = raw_input.mouse_button_down?(@input_button_or_axis)
|
|
22
|
+
result = (@button_down_on_last_poll && !button_down)
|
|
23
|
+
@button_down_on_last_poll = button_down
|
|
24
|
+
cancel_post! unless result
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
value
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def percent_on_screen(raw_input)
|
|
31
|
+
Vector.new(raw_input.mouse_x.to_f / game_state.screen_size.x.to_f, raw_input.mouse_y.to_f / game_state.screen_size.y.to_f)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class MouseValue
|
|
36
|
+
attr_accessor :position, :screen_position, :position_delta, :screen_position_delta
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Jemini
|
|
2
|
+
class SlickInputListener
|
|
3
|
+
java_import 'org.newdawn.slick.InputListener'
|
|
4
|
+
include InputListener
|
|
5
|
+
|
|
6
|
+
def initialize(state)
|
|
7
|
+
@state = state
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def isAcceptingInput
|
|
11
|
+
#@state == GameState.active_state
|
|
12
|
+
true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def method_missing(method, *args)
|
|
16
|
+
return if (method == :inputEnded) || @state != GameState.active_state
|
|
17
|
+
@state.manager(:message_queue).post_message SlickInputMessage.new(method, args)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Jemini
|
|
2
|
+
class SlickInputTranslator
|
|
3
|
+
SLICK_INPUT_TYPE_TRANSLATION = {
|
|
4
|
+
:keyPressed => [:key, :pressed], # which key?
|
|
5
|
+
:keyReleased => [:key, :released],
|
|
6
|
+
:mouseMoved => [:mouse, :moved],
|
|
7
|
+
:mousePressed => [:mouse, :pressed], # which button?
|
|
8
|
+
:mouseReleased => [:mouse, :released],
|
|
9
|
+
:mouseClicked => [:mouse, :clicked],
|
|
10
|
+
:mouseWheelMoved => [:mouse, :wheel_moved],
|
|
11
|
+
:controllerLeftPressed => [:controller, :pressed]
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'thread'
|
|
2
|
+
module Jemini
|
|
3
|
+
|
|
4
|
+
# Message object that is posted to the MessageQueue.
|
|
5
|
+
class Message
|
|
6
|
+
attr_accessor :name, :value, :delta, :to
|
|
7
|
+
|
|
8
|
+
def initialize(name, value, delta=nil, to=nil)
|
|
9
|
+
@name = name
|
|
10
|
+
@value = value
|
|
11
|
+
@delta = delta
|
|
12
|
+
@to = to
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class MessageQueue < Jemini::GameObject
|
|
17
|
+
def load
|
|
18
|
+
@listeners = Hash.new {|h,k| h[k] = []}
|
|
19
|
+
@messages = Queue.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def process_messages(delta)
|
|
23
|
+
until @messages.empty?
|
|
24
|
+
message = @messages.shift
|
|
25
|
+
message.delta = delta
|
|
26
|
+
|
|
27
|
+
@listeners[message.name].each do |listener|
|
|
28
|
+
begin
|
|
29
|
+
if message.to.nil?
|
|
30
|
+
listener[1].call(message)
|
|
31
|
+
else
|
|
32
|
+
listener[1].call(message) if listener[0].respond_to?(:handles_events_for?) && listener[0].handles_events_for?(message.to)
|
|
33
|
+
end
|
|
34
|
+
rescue Exception => e
|
|
35
|
+
# Replace this with a logger
|
|
36
|
+
$stderr << "Error in callback #{listener[1]} for key: #{listener[0]}\n#{e.class} - #{e.message}\n#{e.backtrace.join("\n")}"
|
|
37
|
+
java.lang.System.exit(1)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def post_message(message)
|
|
44
|
+
@messages << message
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Listeners are registered on a certain type of message. This type is arbitrary
|
|
48
|
+
# and can be any symbol. The second parameter is a key that is used to identify
|
|
49
|
+
# the callback when it is removed. The third parameter is the callback object
|
|
50
|
+
# which must be a proc. Alternatively, the second parameter may be omitted and a
|
|
51
|
+
# block passed in its place.
|
|
52
|
+
def add_listener(type, key, callback=nil, &block)
|
|
53
|
+
@listeners[type.to_sym] << [key, callback || block]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def remove_listener(type, key)
|
|
57
|
+
@listeners[type.to_sym].delete_if {|listener| listener.first == key}
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Jemini
|
|
2
|
+
|
|
3
|
+
class NetworkManager < Jemini::GameObject
|
|
4
|
+
|
|
5
|
+
attr_accessor :socket
|
|
6
|
+
|
|
7
|
+
class Peer
|
|
8
|
+
attr_accessor :address, :port
|
|
9
|
+
def initialize(address, port)
|
|
10
|
+
@address, @port = address, port
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
has_behavior :HandlesEvents
|
|
15
|
+
|
|
16
|
+
#An array of all network peers.
|
|
17
|
+
attr_accessor :peers
|
|
18
|
+
|
|
19
|
+
def load
|
|
20
|
+
@peers = []
|
|
21
|
+
@socket = UDPSocket.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# def unload
|
|
25
|
+
# end
|
|
26
|
+
|
|
27
|
+
#Add an address and port to the list of network peers.
|
|
28
|
+
def add_peer(address, port = 5364)
|
|
29
|
+
@peers << Peer.new(address, port)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#Send event to each registered peer.
|
|
33
|
+
def notify_peers(event)
|
|
34
|
+
@peers.each do |peer|
|
|
35
|
+
@socket.send(event, 0, peer.address, peer.port)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|