teien 0.0.2 → 0.0.3

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.
Files changed (49) hide show
  1. data/README.md +11 -6
  2. data/bin/teien +16 -2
  3. data/lib/teien/ai.rb +27 -0
  4. data/lib/teien/animation.rb +34 -0
  5. data/lib/teien/animation_operator.rb +6 -0
  6. data/lib/teien/controller.rb +30 -0
  7. data/lib/teien/dispatcher.rb +22 -0
  8. data/lib/teien/event.rb +60 -0
  9. data/lib/teien/event_router.rb +118 -0
  10. data/lib/teien/garden.rb +60 -172
  11. data/lib/teien/garden_base.rb +117 -0
  12. data/lib/teien/garden_object.rb +119 -136
  13. data/lib/teien/model.rb +34 -0
  14. data/lib/teien/network.rb +108 -0
  15. data/lib/teien/object_info.rb +21 -0
  16. data/lib/teien/physics.rb +47 -39
  17. data/lib/teien/physics_object.rb +57 -0
  18. data/lib/teien/physics_object_factory.rb +170 -0
  19. data/lib/teien/proxy_garden.rb +118 -0
  20. data/lib/teien/remote_info.rb +20 -0
  21. data/lib/teien/sky_dome.rb +15 -0
  22. data/lib/teien/smooth_mover.rb +31 -42
  23. data/lib/teien/synchronizer.rb +26 -0
  24. data/lib/teien/tools.rb +30 -2
  25. data/lib/teien/user_interface.rb +58 -5
  26. data/lib/teien/version.rb +1 -1
  27. data/lib/teien/view.rb +52 -33
  28. data/lib/teien/view_object.rb +67 -0
  29. data/lib/teien/view_object_factory.rb +210 -0
  30. data/lib/teien.rb +62 -14
  31. data/sample/actor/app/ais/actor_ai.rb +112 -0
  32. data/sample/actor/app/controllers/actor_controller.rb +182 -0
  33. data/sample/actor/app/helpers/sinbad/sinbad.rb +176 -0
  34. data/sample/actor/app/helpers/sinbad/sinbad_state.rb +224 -0
  35. data/sample/actor/app/helpers/user_event.rb +75 -0
  36. data/sample/actor/app/models/actor_model.rb +108 -0
  37. data/sample/actor/config/plugins.cfg +19 -0
  38. data/sample/actor/config/resources.cfg +24 -0
  39. data/sample/hello_garden/app/controllers/hello_garden_controller.rb +90 -0
  40. data/sample/hello_garden/app/helpers/user_event.rb +12 -0
  41. data/sample/{standalone/hello_garden/hello_garden.rb → hello_garden/app/models/hello_garden_model.rb} +29 -83
  42. data/sample/{standalone/hello_garden → hello_garden/config}/plugins.cfg +0 -0
  43. data/sample/{standalone/hello_garden → hello_garden/config}/resources.cfg +0 -0
  44. data/sample/hello_garden/run +6 -0
  45. data/teien.gemspec +2 -1
  46. metadata +52 -15
  47. data/lib/teien/light_object.rb +0 -36
  48. data/lib/teien/object_factory.rb +0 -308
  49. data/sample/standalone/hello_garden/run +0 -5
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Teien
2
2
 
3
- Teien will be a platform to make 3D world easily with Ruby.
3
+ Teien will be a platform to make 3D worlds connected by network easily with Ruby.
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,16 +14,21 @@ And then execute:
14
14
 
15
15
  Or install it yourself as:
16
16
 
17
- $ gem install ruby-ogre
18
- $ gem install ruby-bullet
19
- $ gem install teienlib
20
- $ gem install pkg/teien-<version>.gem
17
+ $ gem install eventmachine
18
+ $ gem install ruby-ogre
19
+ $ gem install ruby-bullet
20
+ $ gem install teienlib
21
+ $ rake build
22
+ $ gem install pkg/teien-<version>.gem
21
23
 
22
24
  ## Usage
23
25
 
24
26
  Run a sample application.
25
27
 
26
- $ /var/lib/gems/1.9.1/gems/teien-<version>/sample/standalone/hello_garden/run
28
+ $ mkdir mywork/
29
+ $ cp -r <gems>/teien-<version>/sample/ mywork/
30
+ $ cd mywork/sample/hello_garden/
31
+ $ ./run
27
32
 
28
33
  ## Contributing
29
34
 
data/bin/teien CHANGED
@@ -45,5 +45,19 @@ end
45
45
  $LOAD_PATH.push(libPath)
46
46
  $LOAD_PATH.push("./")
47
47
 
48
- load ARGV[0]
49
-
48
+ require 'teien'
49
+
50
+ case ARGV[0]
51
+ when "server"
52
+ Teien::start_server_garden("0.0.0.0", 11922)
53
+ when "client"
54
+ ip = ARGV[1] ? ARGV[1] : "0.0.0.0"
55
+ port = ARGV[2] ? ARGV[2].to_i : 11922
56
+ Teien::start_client_garden(ip, port)
57
+ when "ai"
58
+ ip = ARGV[1] ? ARGV[1] : "0.0.0.0"
59
+ port = ARGV[2] ? ARGV[2].to_i : 11922
60
+ Teien::start_ai_garden(ip, port)
61
+ when "local"
62
+ Teien::start_local_garden()
63
+ end
data/lib/teien/ai.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'teien'
2
+
3
+ module Teien
4
+
5
+ class Ai
6
+ @@ais = Array.new
7
+ @@loaded_ais = Array.new
8
+
9
+ @garden = nil
10
+
11
+ def initialize(garden)
12
+ @garden = garden
13
+ @garden.register_receiver(self)
14
+ end
15
+
16
+ def self.inherited(klass)
17
+ @@ais.push(klass)
18
+ end
19
+
20
+ def self.load(garden)
21
+ @@ais.each {|ctl|
22
+ @@loaded_ais.push(ctl.new(garden))
23
+ }
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,34 @@
1
+ module Teien
2
+
3
+ class Animation
4
+ attr_accessor :enable
5
+ attr_accessor :blend_mode
6
+ attr_accessor :operators
7
+
8
+ class Operator
9
+ attr_accessor :name
10
+ attr_accessor :speed
11
+ attr_accessor :loop
12
+
13
+ def initialize(name, speed, loop)
14
+ @name = name
15
+ @speed = speed
16
+ @loop = loop
17
+ end
18
+ end
19
+
20
+ def initialize()
21
+ @enable = false
22
+ @blend_mode = Ogre::ANIMBLEND_CUMULATIVE
23
+ @operators = Hash.new
24
+ end
25
+
26
+ def create_operator(operator_name, animation_name, speed, loop)
27
+ unless @operators[operator_name]
28
+ @operators[operator_name] = Operator.new(animation_name, speed, loop)
29
+ end
30
+ return @operators[operator_name]
31
+ end
32
+ end
33
+
34
+ end
@@ -3,6 +3,9 @@ class AnimationOperator
3
3
  BL_MODE_CONCURRENT = 1 # cross fade, blend current animation out while blending next animation in.
4
4
  BL_MODE_FIRSTFRAME = 2 # blend current animation to first frame of next animation, when done, start next animation.
5
5
 
6
+ attr_accessor :name
7
+ attr_accessor :loop
8
+
6
9
  def initialize(entity)
7
10
  @entity = entity
8
11
  @state = nil
@@ -11,6 +14,8 @@ class AnimationOperator
11
14
  @duration = 0.2
12
15
  @timeLeft = 0
13
16
  @complete = false
17
+
18
+ @name = nil
14
19
  @loop = false
15
20
 
16
21
  # @blender = Ogrelet::AnimationBlender.new(entity)
@@ -43,6 +48,7 @@ class AnimationOperator
43
48
  end
44
49
 
45
50
  def play(name, loop)
51
+ @name = name
46
52
  @loop = loop
47
53
 
48
54
  unless @state
@@ -0,0 +1,30 @@
1
+ require 'teien'
2
+
3
+ module Teien
4
+
5
+ class Controller
6
+ @@controllers = Array.new
7
+ @@loaded_controllers = Array.new
8
+
9
+ @garden = nil
10
+ @ui = nil
11
+
12
+ def initialize(garden, ui)
13
+ @garden = garden
14
+ @garden.register_receiver(self)
15
+ @ui = ui
16
+ @ui.register_receiver(self)
17
+ end
18
+
19
+ def self.inherited(klass)
20
+ @@controllers.push(klass)
21
+ end
22
+
23
+ def self.load(garden, ui)
24
+ @@controllers.each {|ctl|
25
+ @@loaded_controllers.push(ctl.new(garden, ui))
26
+ }
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,22 @@
1
+ module Teien
2
+
3
+ module Dispatcher
4
+ def initialize(*args, &block)
5
+ super
6
+ @receivers = Array.new
7
+ end
8
+
9
+ def register_receiver(recv)
10
+ @receivers.push(recv)
11
+ end
12
+
13
+ def notify(method, *argv)
14
+ @receivers.each {|recv|
15
+ if (recv.respond_to?(method))
16
+ recv.method(method).call(*argv)
17
+ end
18
+ }
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,60 @@
1
+ module Event
2
+
3
+ # event
4
+
5
+ class ClientConnected
6
+ end
7
+
8
+ class ClientUnbinded
9
+ end
10
+
11
+ class SyncEnv
12
+ attr_accessor :gravity
13
+ attr_accessor :ambient_light_color
14
+ attr_accessor :sky_dome
15
+
16
+ def initialize(gravity, ambient_light_color, sky_dome)
17
+ @gravity = gravity
18
+ @ambient_light_color = ambient_light_color
19
+ @sky_dome = sky_dome
20
+ end
21
+ end
22
+
23
+ class SyncObject
24
+ attr_accessor :id
25
+ attr_accessor :name
26
+ attr_accessor :mode
27
+
28
+ attr_accessor :object_info
29
+ attr_accessor :physics_info
30
+ attr_accessor :animation_info
31
+
32
+ attr_accessor :pos
33
+ attr_accessor :linear_vel
34
+ attr_accessor :angular_vel
35
+ attr_accessor :quat
36
+ attr_accessor :accel
37
+
38
+
39
+ def initialize(obj)
40
+ @id = obj.id
41
+ @name = obj.name
42
+
43
+ @object_info = obj.object_info
44
+ @physics_info = obj.physics_info
45
+ @animation_info = obj.animation_info
46
+
47
+ @pos = Vector3D.to_self(obj.get_position())
48
+ @linear_vel = Vector3D.to_self(obj.get_linear_velocity())
49
+ @angular_vel = Vector3D.to_self(obj.get_angular_velocity())
50
+ @quat = Quaternion.to_self(obj.get_rotation())
51
+ @accel = obj.get_acceleration()
52
+ end
53
+
54
+ def print
55
+ puts @name
56
+ end
57
+ end
58
+
59
+
60
+ end # module Event
@@ -0,0 +1,118 @@
1
+ require "eventmachine"
2
+ require "teien/event"
3
+ require "teien/network"
4
+
5
+ module Teien
6
+
7
+ ##
8
+ # EventRouter routes events in this region and communicate with the other region routers.
9
+ #
10
+ # ====Usage
11
+ # 1. register a new event type name with registerEventType().
12
+ # 2. register a receiver object which receives the eventType with registerReceiver().
13
+ # The receiver object must have action(event) method.
14
+ # 3. call notify(event) which issues the event.
15
+ # The event must have eventType() method which returns event type name.
16
+ #
17
+ class EventRouter
18
+ attr_accessor :connected_regions
19
+
20
+ def initialize()
21
+ @connected_regions = Array.new
22
+
23
+ @event_type_receiver_hash = {} # event_type => receivers
24
+
25
+ @last_time = 0
26
+ @tick_event = Event::Tick.new(0)
27
+ register_event_type(Event::Tick)
28
+ end
29
+
30
+ def finalize()
31
+ end
32
+
33
+ # eventmachine
34
+ def send_all_regions(obj)
35
+ @connected_regions.each { |c|
36
+ c.send_object(obj)
37
+ }
38
+ end
39
+
40
+ # event_type: the class name of a event.
41
+ def register_event_type(event_type)
42
+ @event_type_receiver_hash[event_type] = Array.new
43
+ end
44
+
45
+ ##
46
+ #
47
+ # The event receiver must have action(anEvent) method.
48
+ #
49
+ def register_receiver(event_name, receiver)
50
+ if (@event_type_receiver_hash.has_key?(event_name))
51
+ @event_type_receiver_hash[event_name].push(receiver)
52
+ else
53
+ print "No such event type(#{event_name}) in EventRouter.\n"
54
+ print "Use EventRouter::register_event_type(event_type) at first.\n"
55
+ end
56
+ end
57
+
58
+ ##
59
+ # The event notified by this method must have a event_type attribute and
60
+ # the event_yype must be registered with register_event_type()
61
+ #
62
+ def notify(event)
63
+ if (@event_type_receiver_hash.has_key?(event.class))
64
+ @event_type_receiver_hash[event.class].each {|receiver|
65
+ receiver.receive_event(event)
66
+ }
67
+ else
68
+ print "No such event type(#{event.class}) in EventRouter.\n"
69
+ print "Use EventRouter::register_event_type(event_type) at first.\n"
70
+ end
71
+ end
72
+
73
+ def run()
74
+ EM.run do
75
+ Signal.trap("INT") { EM.stop; self.finalize() }
76
+ Signal.trap("TERM") { EM.stop; self.finalize() }
77
+
78
+ EM.add_periodic_timer(0) do
79
+ notify(@tick_event)
80
+ # update(delta)
81
+ end
82
+
83
+ # EM.start_server("0.0.0.0", 11922, ServerNetwork, @event_router)
84
+ end
85
+ end
86
+
87
+ # ip: string(ex. "0.0.0.0" means to accept all),
88
+ # port: num
89
+ def start_region(ip, port)
90
+ EM.run do
91
+ Signal.trap("INT") { EM.stop; self.finalize() }
92
+ Signal.trap("TERM") { EM.stop; self.finalize() }
93
+
94
+ EM.add_periodic_timer(0) do
95
+ notify(@tick_event)
96
+ end
97
+
98
+ EM.start_server(ip, port, Network, self)
99
+ end
100
+ end
101
+
102
+ def connect_to_region(ip, port)
103
+ EM.run do
104
+ # setting signals
105
+ Signal.trap("INT") { EM.stop; self.finalize() }
106
+ Signal.trap("TERM") { EM.stop; self.finalize() }
107
+
108
+ # main loop
109
+ EM.add_periodic_timer(0) do
110
+ notify(Event::Tick.new(@tick_event))
111
+ end
112
+
113
+ EM.connect('49.212.146.194', 11922, Network, self)
114
+ end
115
+ end
116
+ end
117
+
118
+ end
data/lib/teien/garden.rb CHANGED
@@ -1,203 +1,91 @@
1
- require "teien/garden_object.rb"
2
- require "teien/light_object.rb"
3
- require "teien/object_factory.rb"
4
- require "teien/view.rb"
5
- #require "teien/server_view.rb"
6
- require "teien/physics.rb"
7
- require "teien/user_interface.rb"
8
- #require "teien/server_user_interface.rb"
1
+ require "teien/garden_base.rb"
2
+ require "teien/network.rb"
3
+ require "teien/event.rb"
9
4
 
10
5
  module Teien
11
6
 
12
- # This is a top object of 3D world.
13
- class Garden
14
- attr_accessor :view
15
- attr_accessor :physics
16
- attr_accessor :resources_cfg
17
- attr_accessor :plugins_cfg
18
- attr_accessor :objects
19
- attr_accessor :object_factory
20
- attr_accessor :is_server
21
-
22
- #
23
- # _script_klass_:: : set a user define class.
24
- #
25
- def initialize(script_klass)
26
- @view = nil
27
- @physics = nil
28
- @script_klass = script_klass
29
-
30
- @resources_cfg = nil
31
- @plugins_cfg = nil
32
- @objects = {}
33
- @object_num = 0
34
-
35
- @object_factory = ObjectFactory.new(self)
36
-
37
- @is_server = false
38
- @debug_draw = false
39
- @quit = false
40
- end
41
-
42
- #
43
- # set a title name on the window title bar.
44
- #
45
- # _title_ :: : set a name(String).
46
- #
47
- def set_window_title(title)
48
- @view.window_title = title unless @is_server
49
- end
50
-
51
- #
52
- # set the gravity of the world.
53
- #
54
- # _grav_ :: : set a vector(Vector3D) as the gravity.
55
- #
56
- def set_gravity(grav)
57
- @physics.set_gravity(grav)
58
- end
59
-
60
- #
61
- # set the ambient light of the world.
62
- #
63
- # _color_:: : set a color(Color).
64
- #
65
- def set_ambient_light(color)
66
- @view.scene_mgr.set_ambient_light(color)
67
- end
68
-
69
- def set_sky_dome(enable, materialName, curvature = 10, tiling = 8, distance = 4000)
70
- @view.scene_mgr.set_sky_dome(enable, materialName, curvature, tiling, distance)
71
- end
72
-
73
- def set_debug_draw(bl)
74
- if (bl)
75
- @debug_draw = bl
76
- @debug_drawer = Teienlib::DebugDrawer.new(@view.scene_mgr)
77
- @physics.dynamicsWorld.set_debug_drawer(@debug_drawer)
78
- end
7
+ class Garden < GardenBase
8
+ def initialize()
9
+ super
79
10
  end
80
11
 
81
- def create_user_interface()
82
- if @is_server
83
- return ServerUserInterface.new(@view)
84
- else
85
- return UserInterface.new(@view)
86
- end
87
- end
88
-
89
- def create_object(name, objectInfo, physicsInfo)
90
- return @object_factory.create_object(name, objectInfo, physicsInfo)
91
- end
92
-
93
- def create_light(name)
94
- return LightObject.new(self, name)
95
- end
12
+ def run(ip = nil, port = 11922)
13
+ return false unless setup()
96
14
 
97
- def add_object(obj, collision_filter = nil)
98
- if (@objects[obj.name] == nil)
99
- if (obj.rigid_body != nil)
100
- if (collision_filter)
101
- @physics.add_rigid_body(obj.rigid_body, collision_filter)
15
+ @last_time = 0
16
+ EM.run do
17
+ EM.add_periodic_timer(0.01) do
18
+ if @last_time == 0
19
+ @last_time = Time.now.to_f
102
20
  else
103
- @physics.add_rigid_body(obj.rigid_body)
21
+ now = Time.now.to_f
22
+ delta = now - @last_time
23
+ @last_time = now
24
+
25
+ unless update(delta)
26
+ EM.stop
27
+ self.finalize()
28
+ end
104
29
  end
105
30
  end
106
- @objects[obj.name] = obj
107
- obj.id = @object_num
108
- @object_num += 1
109
- else
110
- raise RuntimeError, "There is a object with the same name (#{obj.name})"
111
- end
112
- end
113
-
114
- def check_collision(objectA, objectB)
115
- result = @physics.contact_pair_test(objectA.rigid_body, objectB.rigid_body)
116
- return result.isCollided
117
- end
118
31
 
119
- def setup()
120
- if @is_server
121
- @view = ServerView.new(self)
122
- else
123
- @view = View.new(self)
124
- end
125
-
126
- @physics = Physics.new(self)
127
- @script = @script_klass.new(self)
128
-
129
- if @view.setup()
130
- @view.start(@script)
131
- @view.prepare_render_loop()
132
-
133
- @physics.setup()
134
- @script.setup()
135
-
136
- return true
137
- else
138
- return false
139
- end
140
- end
32
+ Signal.trap("INT") { EM.stop; self.finalize() }
33
+ Signal.trap("TERM") { EM.stop; self.finalize() }
141
34
 
142
- #
143
- # mainloop
144
- #
145
- def run()
146
- return false unless setup()
147
-
148
- last_time = Time.now.to_f
149
- while !@quit
150
- now_time = Time.now.to_f
151
- delta = now_time - last_time
152
- last_time = now_time
153
- break unless update(delta)
35
+ if (ip)
36
+ EM.start_server(ip, port, Network, self)
37
+ end
154
38
  end
155
-
156
- finalize()
39
+ end
157
40
 
41
+ def setup()
42
+ @physics.setup(self)
43
+ notify(:setup, self)
158
44
  return true
159
45
  end
160
46
 
161
-
162
47
  def update(delta)
163
- @physics.dynamics_world.debug_draw_world() if @debug_draw
164
-
165
- return @view.update(delta)
48
+ @physics.update(delta)
49
+ @actors.each_value {|actor|
50
+ actor.update(delta)
51
+ }
52
+ notify(:update, delta)
53
+ return !@quit
166
54
  end
167
55
 
168
- # called from view.update()
169
- # This function is divided from update() by the purpose of an optimization,
170
- # which archives to run in parallel with GPU process.
171
- def update_in_frame_rendering_queued(delta)
172
- return false unless @physics.update(delta)
173
-
174
- @objects.each_value {|obj|
175
- obj.update(delta)
176
- }
56
+ # receive handler of Network.
57
+ def receive_event(event, from)
58
+ case event
59
+ when Event::ClientConnected
60
+ from.send_object(Event::SyncEnv.new(@gravity, @ambient_light_color, @sky_dome))
61
+ notify_objects(from)
62
+ end
63
+ notify(:receive_event, event, from)
64
+ end
177
65
 
178
- return @script.update(delta)
66
+ def send_event(event, to = nil)
67
+ if (to)
68
+ to.send_object(event)
69
+ else
70
+ Network::send_all(event)
71
+ end
179
72
  end
180
73
 
181
- def clean_up()
182
- @physics.finalize()
183
- @objects = {}
184
- @view.stop()
74
+ def notify_objects(to = nil)
75
+ @objects.each_value { |obj|
76
+ if to == nil
77
+ Network::send_all(Event::SyncObject.new(obj))
78
+ else
79
+ to.send_object(Event::SyncObject.new(obj))
80
+ end
81
+ }
185
82
  end
186
83
 
187
- # called by Garden class.
188
- # clear all managers.
189
84
  def finalize()
190
85
  @physics.finalize()
191
- @view.root.save_config()
192
- @view.finalize()
193
86
  @objects = {}
194
87
  end
195
-
196
88
 
197
- # quit the current running garden.
198
- def quit()
199
- @quit = true
200
- end
201
89
  end
202
90
 
203
- end # module
91
+ end