diff options
| author | Amir Rajan <[email protected]> | 2021-09-06 14:32:04 -0500 |
|---|---|---|
| committer | Amir Rajan <[email protected]> | 2021-09-06 14:34:34 -0500 |
| commit | 2f5eb6ab368b062dbbde39b3cee6eae23c5452ff (patch) | |
| tree | e2f0b5f4a1ab4919cf5669f6187994489411821a /dragon | |
| parent | aa8d3ac4bdccf522b8082a7fa7d595be2bd54b7d (diff) | |
| download | dragonruby-game-toolkit-contrib-2f5eb6ab368b062dbbde39b3cee6eae23c5452ff.tar.gz dragonruby-game-toolkit-contrib-2f5eb6ab368b062dbbde39b3cee6eae23c5452ff.zip | |
Synced with version 2.26
Diffstat (limited to 'dragon')
| -rw-r--r-- | dragon/args.rb | 17 | ||||
| -rw-r--r-- | dragon/console.rb | 12 | ||||
| -rw-r--r-- | dragon/framerate.rb | 7 | ||||
| -rw-r--r-- | dragon/recording.rb | 260 | ||||
| -rw-r--r-- | dragon/tweetcart.rb | 102 |
5 files changed, 391 insertions, 7 deletions
diff --git a/dragon/args.rb b/dragon/args.rb index 9cf6e33..5bb0ccf 100644 --- a/dragon/args.rb +++ b/dragon/args.rb @@ -200,5 +200,22 @@ module GTK def autocomplete_methods [:inputs, :outputs, :gtk, :state, :geometry, :audio, :grid, :layout, :fn] end + + def method_missing name, *args, &block + if (args.length <= 1) && (@state.as_hash.key? name) + raise <<-S +* ERROR - :#{name} method missing on ~#{self.class.name}~. +The method + :#{name} +with args + #{args} +doesn't exist on #{inspect}. +** POSSIBLE SOLUTION - ~args.state.#{name}~ exists. +Did you forget ~.state~ before ~.#{name}~? +S + end + + super + end end end diff --git a/dragon/console.rb b/dragon/console.rb index b3a2c2a..34183ae 100644 --- a/dragon/console.rb +++ b/dragon/console.rb @@ -434,6 +434,7 @@ S if console_toggle_key_down? args args.inputs.text.clear toggle + args.inputs.keyboard.clear if !@visible end return unless visible? @@ -445,7 +446,16 @@ S @log_offset = 0 if @log_offset < 0 if args.inputs.keyboard.key_down.enter - eval_the_set_command + if slide_progress > 0.5 + # in the event of an exception, the console window pops up + # and is pre-filled with $gtk.reset. + # there is an annoying scenario where the exception could be thrown + # by pressing enter (while playing the game). if you press enter again + # quickly, then the game is reset which closes the console. + # so enter in the console is only evaluated if the slide_progress + # is atleast half way down the page. + eval_the_set_command + end elsif args.inputs.keyboard.key_down.v if args.inputs.keyboard.key_down.control || args.inputs.keyboard.key_down.meta prompt << $gtk.ffi_misc.getclipboard diff --git a/dragon/framerate.rb b/dragon/framerate.rb index a9504a6..ff2f1c5 100644 --- a/dragon/framerate.rb +++ b/dragon/framerate.rb @@ -35,12 +35,7 @@ module GTK if framerate_below_threshold? @last_framerate = current_framerate - if !@framerate_important_notification_happened - log_important framerate_warning_message - else - log framerate_warning_message - end - @framerate_important_notification_happened = true + log framerate_warning_message end end diff --git a/dragon/recording.rb b/dragon/recording.rb new file mode 100644 index 0000000..72d8da9 --- /dev/null +++ b/dragon/recording.rb @@ -0,0 +1,260 @@ +# coding: utf-8 +# Copyright 2019 DragonRuby LLC +# MIT License +# recording.rb has been released under MIT (*only this file*). + +module GTK + # FIXME: Gross + # @gtk + class Replay + # @gtk + def self.start file_name = nil + $recording.start_replay file_name + end + + # @gtk + def self.stop + $recording.stop_replay + end + end + + # @gtk + class Recording + def initialize runtime + @runtime = runtime + @tick_count = 0 + @global_input_order = 1 + end + + def tick + @tick_count += 1 + end + + def start_recording seed_number = nil + if !seed_number + log <<-S +* ERROR: +To start recording, you must provide an integer value to +seed random number generation. +S + $console.set_command "$recording.start SEED_NUMBER" + return + end + + if @is_recording + log <<-S +* ERROR: +You are already recording, first cancel (or stop) the current recording. +S + $console.set_command "$recording.cancel" + return + end + + if @is_replaying + log <<-S +* ERROR: +You are currently replaying a recording, first stop the replay. +S + return + end + + log_info <<-S +Recording has begun with RNG seed value set to #{seed_number}. +To stop recording use stop_recording(filename). +The recording will stop without saving a file if a filename is nil. +S + + $console.set_command "$recording.stop 'replay.txt'" + @runtime.__reset__ + @seed_number = seed_number + @runtime.set_rng seed_number + + @tick_count = 0 + @global_input_order = 1 + @is_recording = true + @input_history = [] + @runtime.notify! "Recording started. When completed, open the console to save it using $recording.stop FILE_NAME (or cancel).", 300 + end + + # @gtk + def start seed_number = nil + start_recording seed_number + end + + def is_replaying? + @is_replaying + end + + def is_recording? + @is_recording + end + + # @gtk + def stop file_name = nil + stop_recording file_name + end + + # @gtk + def cancel + stop_recording_core + @runtime.notify! "Recording cancelled." + end + + def stop_recording file_name = nil + if !file_name + log <<-S +* ERROR: +To please specify a file name when calling: +$recording.stop FILE_NAME + +If you do NOT want to save the recording, call: +$recording.cancel +S + $console.set_command "$recording.stop 'replay.txt'" + return + end + + if !@is_recording + log_info "You are not currently recording. Use start_recording(seed_number) to start recording." + $console.set_command "$recording.start" + return + end + + if file_name + text = "replay_version 2.0\n" + text << "stopped_at #{@tick_count}\n" + text << "seed #{@seed_number}\n" + text << "recorded_at #{Time.now.to_s}\n" + @input_history.each do |items| + text << "#{items}\n" + end + @runtime.write_file file_name, text + @runtime.write_file 'last_replay.txt', text + log_info "The recording has been saved successfully at #{file_name}. You can use start_replay(\"#{file_name}\") to replay the recording." + end + + $console.set_command "$replay.start '#{file_name}'" + stop_recording_core + @runtime.notify! "Recording saved to #{file_name}. To replay it: $replay.start \"#{file_name}\"." + log_info "You can run the replay later on startup using: ./dragonruby mygame --replay #{@replay_file_name}" + nil + end + + def stop_recording_core + @is_recording = false + @input_history = nil + @last_history = nil + @runtime.__reset__ + end + + def start_replay file_name = nil + if !file_name + log <<-S +* ERROR: +Please provide a file name to $recording.start. +S + $console.set_command "$replay.start 'replay.txt'" + return + end + + text = @runtime.read_file file_name + return false unless text + + if text.each_line.first.strip != "replay_version 2.0" + raise "The replay file #{file_name} is not compatible with this version of DragonRuby Game Toolkit. Please recreate the replay (sorry)." + end + + @replay_file_name = file_name + + $replay_data = { input_history: { } } + text.each_line do |l| + if l.strip.length == 0 + next + elsif l.start_with? 'replay_version' + next + elsif l.start_with? 'seed' + $replay_data[:seed] = l.split(' ').last.to_i + elsif l.start_with? 'stopped_at' + $replay_data[:stopped_at] = l.split(' ').last.to_i + elsif l.start_with? 'recorded_at' + $replay_data[:recorded_at] = l.split(' ')[1..-1].join(' ') + elsif l.start_with? '[' + name, value_1, value_2, value_count, id, tick_count = l.strip.gsub('[', '').gsub(']', '').split(',') + $replay_data[:input_history][tick_count.to_i] ||= [] + $replay_data[:input_history][tick_count.to_i] << { + id: id.to_i, + name: name.gsub(':', '').to_sym, + value_1: value_1.to_f, + value_2: value_2.to_f, + value_count: value_count.to_i + } + else + raise "Replay data seems corrupt. I don't know how to parse #{l}." + end + end + + $replay_data[:input_history].keys.each do |key| + $replay_data[:input_history][key] = $replay_data[:input_history][key].sort_by {|input| input[:id]} + end + + @runtime.__reset__ + @runtime.set_rng $replay_data[:seed] + @tick_count = 0 + @is_replaying = true + log_info "Replay has been started." + @runtime.notify! "Replay started [#{@replay_file_name}]." + end + + def stop_replay notification_message = "Replay has been stopped." + if !is_replaying? + log <<-S +* ERROR: +No replay is currently running. Call $replay.start FILE_NAME to start a replay. +S + + $console.set_command "$replay.start 'replay.txt'" + return + end + log_info notification_message + @is_replaying = false + $replay_data = nil + @tick_count = 0 + @global_input_order = 1 + $console.set_command_silent "$replay.start '#{@replay_file_name}'" + @runtime.__reset__ + @runtime.notify! notification_message + end + + def record_input_history name, value_1, value_2, value_count, clear_cache = false + return if @is_replaying + return unless @is_recording + @input_history << [name, value_1, value_2, value_count, @global_input_order, @tick_count] + @global_input_order += 1 + end + + def stage_replay_values + return unless @is_replaying + return unless $replay_data + + if $replay_data[:stopped_at] <= @tick_count + stop_replay "Replay completed [#{@replay_file_name}]. To rerun, bring up the Console and press enter." + return + end + + inputs_this_tick = $replay_data[:input_history][@tick_count] + + if @tick_count.zmod? 60 + log_info "Replay ends in #{($replay_data[:stopped_at] - @tick_count).idiv 60} second(s)." + end + + return unless inputs_this_tick + inputs_this_tick.each do |v| + args = [] + args << v[:value_1] if v[:value_count] >= 1 + args << v[:value_2] if v[:value_count] >= 2 + args << :replay + $gtk.send v[:name], *args + end + end + end +end diff --git a/dragon/tweetcart.rb b/dragon/tweetcart.rb new file mode 100644 index 0000000..9e278b3 --- /dev/null +++ b/dragon/tweetcart.rb @@ -0,0 +1,102 @@ +# coding: utf-8 +# Copyright 2019 DragonRuby LLC +# MIT License +# tweetcart.rb has been released under MIT (*only this file*). + +def $top_level.TICK &block + $top_level.define_method(:tick) do |args| + args.outputs[:scene].w = 160 + args.outputs[:scene].h = 90 + args.outputs[:scene].background_color = [0, 0, 0, 0] + block.call args + args.outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: :scene } + end + + def $top_level.bg! *rgb + r,g,b = rgb + r ||= 255 + g ||= r + b ||= g + $args.outputs.background_color = [r, g, b] + end + + def $top_level.slds + $args.outputs[:scene].sprites + end + + def $top_level.slds! *os + if (os.first.is_a? Numeric) + sld! *os + else + os.each { |o| sld! *o } + end + end + + def $top_level.sld! *params + x, y, w, h, r, g, b, a = nil + if params.length == 2 + x, y = params + elsif params.length == 3 && (params.last.is_a? Array) + x = params[0] + y = params[1] + r, g, b, a = params[2] + r ||= 255 + g ||= r + b ||= g + a ||= 255 + elsif params.length == 4 + x, y, w, h = params + elsif params.length == 5 && (params.last.is_a? Array) + x = params[0] + y = params[1] + w = params[2] + h = params[3] + r,g,b,a = params[4] + r ||= 255 + g ||= r + b ||= g + a ||= 255 + elsif params.length >= 7 + x, y, w, h, r, g, b = params + else + raise "I don't know how to render #{params} with reasonable defaults." + end + + w ||= 1 + h ||= 1 + r ||= 255 + g ||= 255 + b ||= 255 + a ||= 255 + + slds << { x: x, y: y, + w: w, h: h, + r: r, g: g, b: b, a: a, + path: :pixel } + end +end + +=begin +wht = [255] * 3 +red = [255, 0, 0] +blu = [0, 130, 255] +purp = [150, 80, 255] + +TICK { + bg! 0 + + slds << [0, 0, 3, 3, 0, 255, 0, 255] + + sld! 10, 10 + sld! 20, 20, 3, 2 + sld! 30, 30, 2, 2, red + sld! 35, 35, blu + + slds! 40, 40 + + slds! [50, 50], + [60, 60, purp], + [70, 70, 10, 10, wht], + [80, 80, 4, 4, 255, 0, 255] +} +=end |
