tef-animation 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +6 -0
- data/lib/tef/Animation/Animatable.rb +213 -0
- data/lib/tef/Animation/Animation_Handler.rb +180 -0
- data/lib/tef/Animation/Color.rb +112 -0
- data/lib/tef/Animation/Coordinate.rb +49 -0
- data/lib/tef/Animation/Eyes.rb +21 -0
- data/lib/tef/Animation/Value.rb +133 -0
- data/lib/tef/ParameterStack/Override.rb +66 -0
- data/lib/tef/ParameterStack/Stack.rb +149 -0
- data/lib/tef/ProgramSelection/ProgramID.rb +56 -0
- data/lib/tef/ProgramSelection/ProgramSelector.rb +76 -0
- data/lib/tef/ProgramSelection/SequenceCollection.rb +75 -0
- data/lib/tef/ProgramSelection/SoundCollection.rb +108 -0
- data/lib/tef/Sequencing/BaseSequence.rb +72 -0
- data/lib/tef/Sequencing/EventCollector.rb +127 -0
- data/lib/tef/Sequencing/SequencePlayer.rb +91 -0
- data/lib/tef/Sequencing/Sheet.rb +33 -0
- data/lib/tef/Sequencing/SheetSequence.rb +138 -0
- data/lib/tef/animation.rb +11 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3bc7c194c8425278ad0369c293684b65008f293f
|
4
|
+
data.tar.gz: b59ce88b52067a8c5b2b8c2070e7abf408d073e5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9e1c4ed9339a1054e69a5b2074e6f1741da37c3490e7cac055c1f696ad3e6365ecc2b2dda615265df8d3ebd072f1a9b9665d3ca9ef9e31bb9a8fd42c53a5c02a
|
7
|
+
data.tar.gz: 13d28689ecdd5bba1fbb8028076b39ba3623b62b0f7b8f7e38cafdf108941395907790509bef2d340939eb4b1e817561f12d5a01185e95466d20fb2b5e417b74
|
data/README.md
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
|
2
|
+
require_relative 'Value.rb'
|
3
|
+
require_relative 'Color.rb'
|
4
|
+
require_relative 'Coordinate.rb'
|
5
|
+
|
6
|
+
module TEF
|
7
|
+
module Animation
|
8
|
+
class Animatable
|
9
|
+
attr_reader :module_id
|
10
|
+
attr_reader :death_time
|
11
|
+
|
12
|
+
attr_reader :death_delay
|
13
|
+
|
14
|
+
def self.get_attr_list
|
15
|
+
@class_attribute_list ||= {}
|
16
|
+
end
|
17
|
+
def self.get_color_list
|
18
|
+
@class_color_list ||= {}
|
19
|
+
end
|
20
|
+
def self.get_coordinate_list
|
21
|
+
@class_coordinate_list ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.animatable_attr(name, id)
|
25
|
+
get_attr_list()[name] = id
|
26
|
+
|
27
|
+
define_method(name.to_s) do
|
28
|
+
@animatable_attributes[name]
|
29
|
+
end
|
30
|
+
|
31
|
+
define_method("#{name}=") do |arg|
|
32
|
+
if arg.is_a? Numeric
|
33
|
+
@animatable_attributes[name].add = arg
|
34
|
+
else
|
35
|
+
@animatable_attributes[name].from = arg
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.animatable_color(name, id)
|
41
|
+
get_color_list()[name] = id
|
42
|
+
|
43
|
+
define_method(name.to_s) do
|
44
|
+
@animatable_colors[name]
|
45
|
+
end
|
46
|
+
|
47
|
+
define_method("#{name}=") do |arg|
|
48
|
+
@animatable_colors[name].target = arg
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.animatable_coordinate(name, start)
|
53
|
+
get_coordinate_list()[name] = start
|
54
|
+
|
55
|
+
define_method(name.to_s) do
|
56
|
+
@animatable_coordinates[name]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize()
|
61
|
+
@animatable_attributes = {}
|
62
|
+
@animatable_colors = {}
|
63
|
+
@animatable_coordinates = {}
|
64
|
+
|
65
|
+
self.class.get_attr_list.each do |key, val|
|
66
|
+
@animatable_attributes[key] = Value.new(val)
|
67
|
+
end
|
68
|
+
|
69
|
+
self.class.get_color_list.each do |key, val|
|
70
|
+
@animatable_colors[key] = Color.new(val)
|
71
|
+
end
|
72
|
+
|
73
|
+
self.class.get_coordinate_list.each do |key, offset|
|
74
|
+
@animatable_coordinates[key] = Coordinate.new(offset)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def death_time=(n_time)
|
79
|
+
raise ArgumentError, 'Must be a Time!' unless n_time.is_a? Time || n_time.nil?
|
80
|
+
|
81
|
+
return if n_time == @death_time
|
82
|
+
|
83
|
+
@death_time = n_time
|
84
|
+
@death_time_changed = true
|
85
|
+
end
|
86
|
+
|
87
|
+
def die_in(t)
|
88
|
+
if t.nil?
|
89
|
+
self.death_time = nil
|
90
|
+
@death_delay = nil
|
91
|
+
|
92
|
+
return
|
93
|
+
end
|
94
|
+
|
95
|
+
raise ArgumentError, "Time must be num!" unless t.is_a? Numeric
|
96
|
+
|
97
|
+
self.death_time = Time.now() + t
|
98
|
+
@death_delay = t
|
99
|
+
end
|
100
|
+
|
101
|
+
def die!
|
102
|
+
self.death_time = Time.at(0)
|
103
|
+
end
|
104
|
+
|
105
|
+
def configure(h = nil, **opts)
|
106
|
+
h ||= opts;
|
107
|
+
|
108
|
+
raise ArgumentError, 'Config must be a hash!' unless h.is_a? Hash
|
109
|
+
|
110
|
+
h.each do |key, data|
|
111
|
+
value = @animatable_attributes[key] ||
|
112
|
+
@animatable_colors[key] ||
|
113
|
+
@animatable_coordinates[key]
|
114
|
+
|
115
|
+
raise ArgumentError, "Parameter #{key} does not exist!" unless value
|
116
|
+
|
117
|
+
value.configure(data);
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def creation_string
|
122
|
+
""
|
123
|
+
end
|
124
|
+
|
125
|
+
def all_animatable_attributes
|
126
|
+
out = @animatable_attributes.values
|
127
|
+
out += @animatable_coordinates.values.map(&:animatable_attributes)
|
128
|
+
|
129
|
+
out.flatten
|
130
|
+
end
|
131
|
+
|
132
|
+
def module_id=(new_str)
|
133
|
+
unless new_str =~ /^S[\d]{1,3}M[\d]{1,3}$/ || new_str.nil?
|
134
|
+
raise ArgumentError, 'Target must be a valid Animation Value'
|
135
|
+
end
|
136
|
+
|
137
|
+
all_animatable_attributes.each do |value|
|
138
|
+
value.module_id = new_str
|
139
|
+
end
|
140
|
+
|
141
|
+
die_in @death_delay if @death_delay
|
142
|
+
|
143
|
+
@module_id = new_str
|
144
|
+
end
|
145
|
+
|
146
|
+
def death_time_string
|
147
|
+
return nil unless @death_time_changed
|
148
|
+
|
149
|
+
@death_time_changed = false
|
150
|
+
|
151
|
+
return "#{@module_id} N;" if @death_time.nil?
|
152
|
+
|
153
|
+
remaining_time = (@death_time - Time.now()).round(2)
|
154
|
+
|
155
|
+
"#{@module_id} #{remaining_time};"
|
156
|
+
end
|
157
|
+
|
158
|
+
def get_set_strings()
|
159
|
+
return [] unless @module_id
|
160
|
+
|
161
|
+
out_elements = []
|
162
|
+
|
163
|
+
all_animatable_attributes.each do |val|
|
164
|
+
o_str = val.set_string
|
165
|
+
next if o_str.nil?
|
166
|
+
|
167
|
+
out_elements << { module: @module_id, value: val.ID, str: o_str };
|
168
|
+
end
|
169
|
+
|
170
|
+
out_elements
|
171
|
+
end
|
172
|
+
|
173
|
+
def get_setc_strings()
|
174
|
+
return [] unless @module_id
|
175
|
+
|
176
|
+
out_elements = []
|
177
|
+
|
178
|
+
@animatable_colors.values.each do |val|
|
179
|
+
o_str = val.set_string
|
180
|
+
next if o_str.nil?
|
181
|
+
|
182
|
+
out_elements << "#{@module_id}#{o_str}"
|
183
|
+
end
|
184
|
+
|
185
|
+
out_elements
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
class Box < Animatable
|
190
|
+
animatable_color :color, 0
|
191
|
+
|
192
|
+
animatable_attr :rotation, 0
|
193
|
+
animatable_attr :up, 1
|
194
|
+
animatable_attr :down, 2
|
195
|
+
animatable_attr :left, 3
|
196
|
+
animatable_attr :right, 4
|
197
|
+
|
198
|
+
animatable_coordinate :x_dir, 0xC000
|
199
|
+
animatable_coordinate :y_dir, 0xC100
|
200
|
+
animatable_coordinate :center, 0xC200
|
201
|
+
|
202
|
+
def initialize(layer_no = 0)
|
203
|
+
super();
|
204
|
+
|
205
|
+
@layer = layer_no;
|
206
|
+
end
|
207
|
+
|
208
|
+
def creation_string
|
209
|
+
"BOX #{@module_id} #{@layer}"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
|
2
|
+
require 'xasin_logger'
|
3
|
+
|
4
|
+
require_relative 'Animatable.rb'
|
5
|
+
|
6
|
+
module TEF
|
7
|
+
module Animation
|
8
|
+
class Handler
|
9
|
+
include XasLogger::Mix
|
10
|
+
|
11
|
+
def initialize(furcoms_bus)
|
12
|
+
@furcoms = furcoms_bus
|
13
|
+
|
14
|
+
@animation_mutex = Mutex.new
|
15
|
+
@active_animations = {}
|
16
|
+
|
17
|
+
@pending_deletions = {}
|
18
|
+
@pending_creations = {}
|
19
|
+
|
20
|
+
init_x_log('Animation Handler')
|
21
|
+
end
|
22
|
+
|
23
|
+
def clean_key(key)
|
24
|
+
key = 'S%<S>dM%<M>d' % key if key.is_a? Hash
|
25
|
+
|
26
|
+
unless key =~ /^S[\d]{1,3}M[\d]{1,3}$/
|
27
|
+
raise ArgumentError, 'Target must be a valid Animation Value'
|
28
|
+
end
|
29
|
+
|
30
|
+
key
|
31
|
+
end
|
32
|
+
|
33
|
+
def [](key)
|
34
|
+
@active_animations[clean_key key]
|
35
|
+
end
|
36
|
+
|
37
|
+
def []=(key, new_obj)
|
38
|
+
@animation_mutex.synchronize {
|
39
|
+
key = clean_key key
|
40
|
+
|
41
|
+
@active_animations[key]&.module_id = nil;
|
42
|
+
|
43
|
+
if new_obj.nil?
|
44
|
+
@pending_deletions[key] = true
|
45
|
+
|
46
|
+
elsif new_obj.is_a? Animatable
|
47
|
+
new_obj.module_id = key
|
48
|
+
|
49
|
+
@active_animations[key] = new_obj
|
50
|
+
@pending_creations[key] = new_obj.creation_string
|
51
|
+
else
|
52
|
+
raise ArgumentError, 'New animation object is of invalid type'
|
53
|
+
end
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
private def join_and_send(topic, data)
|
58
|
+
return if data.empty?
|
59
|
+
|
60
|
+
out_str = '';
|
61
|
+
data.each do |str|
|
62
|
+
if(out_str.length + str.length > 200)
|
63
|
+
@furcoms.send_message topic, out_str
|
64
|
+
out_str = ''
|
65
|
+
end
|
66
|
+
|
67
|
+
out_str += str
|
68
|
+
end
|
69
|
+
|
70
|
+
@furcoms.send_message topic, out_str
|
71
|
+
end
|
72
|
+
|
73
|
+
# TODO Replace this with a time-synched system
|
74
|
+
# using the main synch time
|
75
|
+
private def update_deaths
|
76
|
+
death_reconfigs = [];
|
77
|
+
|
78
|
+
@animation_mutex.synchronize {
|
79
|
+
@active_animations.each do |key, animation|
|
80
|
+
if (!animation.death_time.nil?) && animation.death_time < Time.now()
|
81
|
+
@pending_deletions[key] = :silent
|
82
|
+
end
|
83
|
+
|
84
|
+
new_death = animation.death_time_string
|
85
|
+
next if new_death.nil?
|
86
|
+
|
87
|
+
death_reconfigs << new_death
|
88
|
+
end
|
89
|
+
}
|
90
|
+
|
91
|
+
deletions = []
|
92
|
+
@pending_deletions.each do |key, val|
|
93
|
+
deletions << "#{key};" unless val == :silent
|
94
|
+
@active_animations.delete key
|
95
|
+
end
|
96
|
+
@pending_deletions = {}
|
97
|
+
|
98
|
+
join_and_send('DTIME', death_reconfigs)
|
99
|
+
join_and_send('DELETE', deletions)
|
100
|
+
end
|
101
|
+
|
102
|
+
private def update_creations
|
103
|
+
@pending_creations.each do |key, val|
|
104
|
+
@furcoms.send_message('NEW', val)
|
105
|
+
end
|
106
|
+
|
107
|
+
@pending_creations = {}
|
108
|
+
end
|
109
|
+
|
110
|
+
private def optimize_and_send(messages)
|
111
|
+
last_change = {}
|
112
|
+
out_str = '';
|
113
|
+
can_optimize = false
|
114
|
+
|
115
|
+
messages.each do |change|
|
116
|
+
opt_string = change[:str]
|
117
|
+
|
118
|
+
can_optimize = false if last_change[:module] != change[:module]
|
119
|
+
can_optimize = false if last_change[:value] != (change[:value] - 1)
|
120
|
+
can_optimize = false if (out_str.length + opt_string.length) > 200
|
121
|
+
can_optimize = false if opt_string[0] == 'S'
|
122
|
+
|
123
|
+
opt_string = "#{change[:module]}V#{change[:value].to_s(16)} #{opt_string}" unless can_optimize
|
124
|
+
|
125
|
+
if opt_string.length + out_str.length > 200
|
126
|
+
@furcoms.send_message 'SET', out_str
|
127
|
+
out_str = ''
|
128
|
+
end
|
129
|
+
|
130
|
+
out_str += opt_string
|
131
|
+
|
132
|
+
|
133
|
+
can_optimize = true
|
134
|
+
last_change = change
|
135
|
+
end
|
136
|
+
|
137
|
+
@furcoms.send_message 'SET', out_str
|
138
|
+
end
|
139
|
+
|
140
|
+
private def update_values()
|
141
|
+
pending_changes = []
|
142
|
+
|
143
|
+
@animation_mutex.synchronize {
|
144
|
+
@active_animations.each do |key, anim|
|
145
|
+
pending_changes += anim.get_set_strings
|
146
|
+
end
|
147
|
+
}
|
148
|
+
|
149
|
+
return if pending_changes.empty?
|
150
|
+
x_logd "Pending changes are #{pending_changes}"
|
151
|
+
|
152
|
+
optimize_and_send pending_changes
|
153
|
+
end
|
154
|
+
|
155
|
+
private def update_colors
|
156
|
+
pending_changes = []
|
157
|
+
|
158
|
+
@animation_mutex.synchronize {
|
159
|
+
@active_animations.each do |key, anim|
|
160
|
+
pending_changes += anim.get_setc_strings
|
161
|
+
end
|
162
|
+
}
|
163
|
+
|
164
|
+
return if pending_changes.empty?
|
165
|
+
x_logd "Pending changes are #{pending_changes}"
|
166
|
+
|
167
|
+
join_and_send 'CSET', pending_changes
|
168
|
+
end
|
169
|
+
|
170
|
+
def update_tick()
|
171
|
+
update_creations
|
172
|
+
|
173
|
+
update_deaths
|
174
|
+
|
175
|
+
update_values
|
176
|
+
update_colors
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
|
2
|
+
module TEF
|
3
|
+
module Animation
|
4
|
+
class Color
|
5
|
+
PARAM_TYPES = [:jump, :velocity, :target, :delay_a, :delay_b];
|
6
|
+
|
7
|
+
attr_reader :ID
|
8
|
+
|
9
|
+
attr_reader :module_id
|
10
|
+
|
11
|
+
def initialize(value_num)
|
12
|
+
@ID = value_num;
|
13
|
+
|
14
|
+
@current = Hash.new(0);
|
15
|
+
@changes = {}
|
16
|
+
|
17
|
+
@is_animated = false;
|
18
|
+
end
|
19
|
+
|
20
|
+
def module_id=(new_id)
|
21
|
+
@module_id = new_id
|
22
|
+
|
23
|
+
PARAM_TYPES.each do |key|
|
24
|
+
@changes[:key] = true if @current[key] != 0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def total_id()
|
29
|
+
"#{@module_id}V#{@ID}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def generic_set(key, value)
|
33
|
+
raise ArgumentError, 'Key does not exist!' unless PARAM_TYPES.include? key
|
34
|
+
raise ArgumentError, "Input must be numeric!" unless value.is_a? Numeric
|
35
|
+
|
36
|
+
return if ![:jump, :velocity].include?(key) && value == @current[key]
|
37
|
+
|
38
|
+
if [:delay_a, :delay_b].include? key
|
39
|
+
@is_animated = true
|
40
|
+
end
|
41
|
+
|
42
|
+
@current[key] = value
|
43
|
+
@changes[key] = true
|
44
|
+
end
|
45
|
+
|
46
|
+
PARAM_TYPES.each do |key|
|
47
|
+
define_method(key.to_s) do
|
48
|
+
@current[key]
|
49
|
+
end
|
50
|
+
|
51
|
+
define_method("#{key}=") do |input|
|
52
|
+
generic_set key, input
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def configure(data)
|
57
|
+
if data.is_a? Numeric
|
58
|
+
self.target = data
|
59
|
+
elsif data.is_a? Hash
|
60
|
+
data.each do |key, value|
|
61
|
+
generic_set key, value
|
62
|
+
end
|
63
|
+
else
|
64
|
+
raise ArgumentError, 'Config data must be Hash or Numeric'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def has_changes?
|
69
|
+
return !@changes.empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
private def rcut(value)
|
73
|
+
value.to_s.gsub(/(\.)0+$/, '')
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_string()
|
77
|
+
return nil unless has_changes?
|
78
|
+
|
79
|
+
if !@is_animated
|
80
|
+
return nil unless @changes[:target]
|
81
|
+
|
82
|
+
out_str = "V#{@ID} J#{@current[:target].to_s(16)};"
|
83
|
+
|
84
|
+
@changes = {}
|
85
|
+
|
86
|
+
return out_str
|
87
|
+
end
|
88
|
+
|
89
|
+
out_str = ["V#{@ID}"];
|
90
|
+
|
91
|
+
out_str << "J#{@current[:jump].to_s(16)}" if @changes[:jump]
|
92
|
+
out_str << "V#{@current[:velocity].to_s(16)}" if @changes[:velocity]
|
93
|
+
|
94
|
+
config_strs = [];
|
95
|
+
config_strs_out = [];
|
96
|
+
[:target, :delay_a, :delay_b].each do |k|
|
97
|
+
if k == :target
|
98
|
+
config_strs << @current[k].to_s(16)
|
99
|
+
else
|
100
|
+
config_strs << rcut(@current[k])
|
101
|
+
end
|
102
|
+
|
103
|
+
config_strs_out = config_strs.dup if @changes[k]
|
104
|
+
end
|
105
|
+
|
106
|
+
@changes = {}
|
107
|
+
|
108
|
+
(out_str + config_strs_out).join(' ') + ';'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|