tef-animation 0.1.0
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.
- 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
|