25 Commits

Author SHA1 Message Date
95fc6272b8 tweaks to release.rake 2020-05-07 12:33:09 -05:00
d3603947cc Added semi-automatic game:release rake task 2020-05-07 11:46:54 -05:00
029d9b1951 Updated Gems 2020-05-07 08:31:11 -05:00
6520051938 Added Editor model 2020-05-06 21:33:17 -05:00
8d956131d1 Made 'use_shaders' debug option work 2020-05-06 21:32:55 -05:00
7f16efe0a4 Update README 2020-05-06 20:00:20 -05:00
c92ea9ec73 Added screenshots 2020-05-06 19:49:51 -05:00
c9ba1ab94a Fixed typo in Overlay 2020-05-06 12:53:55 -05:00
2000f601d8 Tweak SettingsMenu and AssetViewer MainMenu 2020-05-06 12:02:13 -05:00
a078645b94 Refreshed a few menus, stubbed Settings menu 2020-05-05 10:46:23 -05:00
c1eb02a106 Fixed game not launching when packaged 2020-05-04 11:56:26 -05:00
a3b4c6e651 Update Boot/Close to use Menu constants 2020-05-04 11:32:17 -05:00
fd3785cdcd Updated menus, added background to Tools 2020-05-04 11:13:51 -05:00
06fb2c0e43 Stub NetworkManager, remove pixel test image, added icon for releasy 2020-05-04 09:59:01 -05:00
d524c21332 Enable server to require i-mic-fps.rb without launching game, fixed missing update method from connection/server, update gemfile to add releasy and rake 2020-05-04 09:28:57 -05:00
85dd90b2f4 Added HUD widgets, make Boot and Close use button_up instead of button_down 2020-05-04 08:57:58 -05:00
1629cf4605 Added Close game state, tweaked Boot state 2020-05-04 07:34:24 -05:00
f3c3a1047f Tweaked Boot state transition effect 2020-05-03 23:39:52 -05:00
face4b092a Added boot screen, added logo 2020-05-03 23:25:33 -05:00
75185425b6 Stubbed out files for networking 2020-05-03 21:18:08 -05:00
bb21de2e2a Use a bullet symbol for Overlay spacer 2020-05-03 09:55:26 -05:00
c53d42166b Use glLineWidth for wireframe rendering, use LoadingState for MapEditor 2020-05-03 09:49:57 -05:00
c05009a000 Moved renderer stats to Overlay 2020-05-03 09:40:51 -05:00
9593d341bf Added overlay for future fps and stats display 2020-05-02 17:34:19 -05:00
27de5667be Initial work on map editor 2020-05-02 15:59:26 -05:00
55 changed files with 6114 additions and 128 deletions

View File

@@ -1,8 +1,13 @@
source "https://rubygems.org"
gem "rake"
gem "opengl-bindings", require: "opengl"
gem "cyberarm_engine", git: "https://github.com/cyberarm/cyberarm_engine"
gem "nokogiri", ">= 1.11.0.rc1"
gem "async-websocket"
group(:packaging) do
gem "releasy", github: "gosu/releasy"
gem "ocra"
gem "rubyzip"
gem "excon"
end

View File

@@ -1,32 +1,84 @@
GIT
remote: https://github.com/cyberarm/cyberarm_engine
revision: d8551c7428da98bb7da76c138e5fbde50ef0137f
revision: 0850336e55891f1f10dcb10e3b4b42e5f7379b33
specs:
cyberarm_engine (0.13.1)
cyberarm_engine (0.14.0)
gosu (~> 0.15.0)
gosu_more_drawables (~> 0.3)
GIT
remote: https://github.com/gosu/releasy.git
revision: e8a24c079c4930c6ddbab17fc444027ba41491ca
specs:
releasy (0.2.3)
bundler (>= 1.2.1)
cri (~> 2.1.0)
ocra (~> 1.3.0)
rake (>= 0.9.2.2)
GEM
remote: https://rubygems.org/
specs:
async (1.26.0)
console (~> 1.0)
nio4r (~> 2.3)
timers (~> 4.1)
async-http (0.52.2)
async (~> 1.25)
async-io (~> 1.28)
async-pool (~> 0.2)
protocol-http (~> 0.19.0)
protocol-http1 (~> 0.13.0)
protocol-http2 (~> 0.14.0)
async-io (1.29.0)
async (~> 1.14)
async-pool (0.3.1)
async (~> 1.25)
async-websocket (0.14.0)
async-http (~> 0.51)
async-io (~> 1.23)
protocol-websocket (~> 0.7.0)
console (1.8.2)
cri (2.1.0)
excon (0.73.0)
gosu (0.15.1)
gosu (0.15.1-x64-mingw32)
mini_portile2 (2.4.0)
nokogiri (1.11.0.rc1)
mini_portile2 (~> 2.4.0)
nokogiri (1.11.0.rc1-x64-mingw32)
mini_portile2 (~> 2.4.0)
gosu_more_drawables (0.3.0)
mini_portile2 (2.5.0)
nio4r (2.5.2)
nokogiri (1.11.0.rc2)
mini_portile2 (~> 2.5.0)
nokogiri (1.11.0.rc2-x64-mingw32)
ocra (1.3.11)
opengl-bindings (1.6.9)
opengl-bindings (1.6.10)
protocol-hpack (1.4.2)
protocol-http (0.19.0)
protocol-http1 (0.13.0)
protocol-http (~> 0.19)
protocol-http2 (0.14.0)
protocol-hpack (~> 1.4)
protocol-http (~> 0.18)
protocol-websocket (0.7.4)
protocol-http (~> 0.2)
protocol-http1 (~> 0.2)
rake (13.0.1)
rubyzip (2.3.0)
timers (4.3.0)
PLATFORMS
ruby
x64-mingw32
DEPENDENCIES
async-websocket
cyberarm_engine!
excon
nokogiri (>= 1.11.0.rc1)
ocra
opengl-bindings
rake
releasy!
rubyzip
BUNDLED WITH
2.1.4

View File

@@ -1,5 +1,7 @@
# I-MIC FPS
An endeavor to create a multiplayer first-person-shooter in pure Ruby; Using C extensions only for Rendering, Sound, and Input. ([Gosu](https://libgosu.org) and [opengl-bindings](https://github.com/vaiorabbit/ruby-opengl/))
Creating a multiplayer first-person-shooter in pure Ruby; Using C extensions only for Rendering, Sound, and Input. ([Gosu](https://libgosu.org) and [opengl-bindings](https://github.com/vaiorabbit/ruby-opengl/))
![](https://raw.githubusercontent.com/cyberarm/i-mic-fps/master/screenshots/screenshot-game.png)
## Using
Requires a Ruby runtime that supports the gosu and opengl-bindings C-extensions (truffleruby 1.0.0-rc12 did not work when tested. Rubinus was not tested.)

View File

@@ -1,10 +1,16 @@
require "json"
require "tmpdir"
require "fileutils"
require "zip"
require "excon"
require "releasy"
require 'bundler/setup' # Releasy requires that your application uses bundler.
require_relative "lib/version"
Releasy::Project.new do
name "I-MIC FPS"
version "#{IMICFPS::VERSION}"
name IMICFPS::NAME
version IMICFPS::VERSION
executable "i-mic-fps.rb"
files ["lib/**/*.*", "assets/**/*.*", "blends/**/*.*", "shaders/**/*.*", "static/**/*.*", "maps/**/*.*", "data/**/*.*"]
@@ -12,7 +18,7 @@ Releasy::Project.new do
verbose
add_build :windows_folder do
# icon "assets/icon.ico"
icon "static/icon.ico"
executable_type :console # Assuming you don't want it to run with a console window.
add_package :exe # Windows self-extracting archive.
end

View File

@@ -1,5 +1,8 @@
require "gosu"
require_relative "lib/objects/text"
begin
require_relative "../cyberarm_engine/lib/cyberarm_engine"
rescue LoadError
require "cyberarm_engine"
end
class Window < Gosu::Window
def initialize
@@ -9,8 +12,8 @@ class Window < Gosu::Window
@slope = 250
@color_step = 10
@base_color = Gosu::Color.rgb(255, 127, 0)
@title = Text.new("I-MIC FPS", color: Gosu::Color.rgb(255,127,0), size: 100, x: 0, y: 15, alignment: :center)
@singleplayer = Text.new("Singleplayer", color: Gosu::Color.rgb(0,127,127), size: 50, x: 0, y: 150, alignment: :center)
@title = CyberarmEngine::Text.new("I-MIC FPS", color: Gosu::Color.rgb(255,127,0), size: 100, x: 0, y: 15, alignment: :center)
@singleplayer = CyberarmEngine::Text.new("Singleplayer", color: Gosu::Color.rgb(0,127,127), size: 50, x: 0, y: 150, alignment: :center)
end
def draw

View File

@@ -0,0 +1,3 @@
name: "editor"
model: "editor.obj"
collision: "mesh"

View File

@@ -0,0 +1,32 @@
# Blender MTL File: 'editor.blend'
# Material Count: 3
newmtl body
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.011935 0.113782 0.401969
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
newmtl energy
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.653036 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
newmtl eye
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.710554 0.177754 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2

File diff suppressed because it is too large Load Diff

BIN
blends/editor.blend Normal file

Binary file not shown.

BIN
blends/editor.blend1 Normal file

Binary file not shown.

9
i-mic-fps-server.rb Normal file
View File

@@ -0,0 +1,9 @@
IMICFPS_SERVER_MODE = true
require_relative "i-mic-fps"
director = IMICFPS::Networking::Director.new(mode: :server, hostname: "0.0.0.0", port: 56789, interface: IMICFPS::Networking::MemoryServer)
director.define_singleton_method(:tick) do |dt|
puts "Ticked: #{dt}"
end
director.run.join

View File

@@ -3,10 +3,13 @@ require "yaml"
require "json"
require "abbrev"
require "time"
require "socket"
require "tmpdir"
require "opengl"
require "glu"
require "nokogiri"
require "async/websocket"
begin
require_relative "../cyberarm_engine/lib/cyberarm_engine"
@@ -56,12 +59,21 @@ require_relative "lib/ui/console"
require_relative "lib/ui/menus/main_menu"
require_relative "lib/ui/menus/settings_menu"
require_relative "lib/ui/menus/extras_menu"
require_relative "lib/ui/menus/multiplayer_menu"
require_relative "lib/ui/menus/level_select_menu"
require_relative "lib/ui/menus/game_pause_menu"
require_relative "lib/states/game_states/boot"
require_relative "lib/states/game_states/close"
require_relative "lib/states/game_states/game"
require_relative "lib/states/game_states/loading_state"
require_relative "lib/hud"
require_relative "lib/hud/widget"
require_relative "lib/hud/widgets/ammo"
require_relative "lib/hud/widgets/radar"
require_relative "lib/hud/widgets/health"
require_relative "lib/subscription"
require_relative "lib/publisher"
require_relative "lib/event"
@@ -106,11 +118,39 @@ require_relative "lib/scenes/turn_table"
require_relative "lib/crosshair"
require_relative "lib/demo"
require_relative "lib/networking/director"
require_relative "lib/networking/packet_handler"
require_relative "lib/networking/client"
require_relative "lib/networking/server"
require_relative "lib/networking/connection"
require_relative "lib/networking/backends/memory_server"
require_relative "lib/networking/backends/memory_connection"
require_relative "lib/overlay"
require_relative "lib/window"
require_relative "lib/tools/asset_viewer"
require_relative "lib/tools/map_editor"
# Don't launch game if IMICFPS_SERVER_MODE is defined
# or if game is being packaged
def prevent_launch?
packaging_lockfile = File.expand_path("i-mic-fps-packaging.lock", Dir.tmpdir)
m = "Game client not launched"
return [true, "#{m}: Server is running"] if defined?(IMICFPS_SERVER_MODE) && IMICFPS_SERVER_MODE
return [true, "#{m}: Packaging is running"] if defined?(Ocra)
if File.exist?(packaging_lockfile) && File.read(packaging_lockfile).strip == IMICFPS::VERSION
return [true, "#{m}: Packaging lockfile is present (#{packaging_lockfile})"]
end
return [false, ""]
end
unless prevent_launch?[0]
if ARGV.join.include?("--profile")
begin
require "ruby-prof"
@@ -125,3 +165,6 @@ if ARGV.join.include?("--profile")
else
IMICFPS::Window.new.show
end
else
puts prevent_launch?[1]
end

View File

@@ -39,8 +39,53 @@ class IMICFPS
def draw_quad(*args)
window.draw_quad(*args)
end
def fill(color = Gosu::Color::WHITE)
draw_rect(0, 0, window.width, window.height, color)
def fill(color = Gosu::Color::WHITE, z = 0)
draw_rect(0, 0, window.width, window.height, color, z)
end
def fill_quad(x1, y1, x2, y2, x3, y3, x4, y4, color = Gosu::Color::WHITE, z = 0, mode = :default)
draw_quad(
x1,y1, color,
x2,y2, color,
x3,y3, color,
x4,y4, color,
z, mode
)
end
def menu_background(primary_color, accent_color, color_step, transparency, bar_size, slope)
((Gosu.screen_height + slope) / bar_size).times do |i|
color = Gosu::Color.rgba(
primary_color.red - i * color_step,
primary_color.green - i * color_step,
primary_color.blue - i * color_step,
transparency
)
fill_quad(
0, i * bar_size,
0, slope + (i * bar_size),
window.width / 2, (-slope) + (i * bar_size),
window.width / 2, i * bar_size,
color,
-2
)
fill_quad(
window.width, i * bar_size,
window.width, slope + (i * bar_size),
window.width / 2, (-slope) + (i * bar_size),
window.width / 2, i * bar_size,
color,
-2
)
end
Gosu.draw_quad(
0, 0, primary_color,
window.width, 0, primary_color,
window.width, window.height, accent_color,
0, window.height, accent_color,
-2
)
end
def gl_error?

23
lib/hud.rb Normal file
View File

@@ -0,0 +1,23 @@
class IMICFPS
class HUD
def initialize(player)
@ammo = AmmoWidget.new({ player: player })
@radar = RadarWidget.new({ player: player })
@health = HealthWidget.new({ player: player })
@hud_elements = [
@ammo,
@radar,
@health,
]
end
def draw
@hud_elements.each(&:draw)
end
def update
@hud_elements.each(&:update)
end
end
end

25
lib/hud/widget.rb Normal file
View File

@@ -0,0 +1,25 @@
class IMICFPS
class HUD
class Widget
include CommonMethods
attr_reader :options
def initialize(options = {})
@options = options
@player = options[:player]
@margin = 10
setup
end
def setup
end
def draw
end
def update
end
end
end
end

29
lib/hud/widgets/ammo.rb Normal file
View File

@@ -0,0 +1,29 @@
class IMICFPS
class HUD
class AmmoWidget < HUD::Widget
def setup
@text = Text.new("")
@background = Gosu::Color.new(0x88222222)
end
def draw
Gosu.draw_rect(
@text.x - @margin, @text.y - @margin,
@text.width + @margin * 2, @text.height + @margin * 2,
@background
)
@text.draw
end
def update
if (Gosu.milliseconds / 1000.0) % 1.0 >= 0.9
random = "#{rand(0..999)}".rjust(3, "0")
@text.text = "Pistol\nAMMO: #{random}"
end
@text.x = window.width - (@margin * 2 + @text.width)
@text.y = window.height - (@margin * 2 + @text.height)
end
end
end
end

48
lib/hud/widgets/health.rb Normal file
View File

@@ -0,0 +1,48 @@
class IMICFPS
class HUD
class HealthWidget < HUD::Widget
def setup
@spacer = 0
@text = Text.new("")
@width = 512
@height = 24
@slant = 32
@color = Gosu::Color.rgba(100, 100, 200, 128)
@shield = Gosu::Color.rgba(200, 100, 50, 200)
@health = 0.0
end
def draw
@text.draw
fill_quad(
window.width / 2 - @width / 2, @spacer, # TOP LEFT
window.width / 2 + @width / 2, @spacer, # TOP RIGHT
window.width / 2 + @width / 2 - @slant, @spacer + @height, # BOTTOM RIGHT
window.width / 2 - @width / 2 + @slant, @spacer + @height, # BOTTOM LEFT
@color
)
# Current Health
fill_quad(
window.width / 2 - @width / 2, @spacer, # TOP LEFT
(window.width / 2 - @width / 2) + @width * @health, @spacer, # TOP RIGHT
(window.width / 2 - @width / 2) + @width * @health - @slant, @spacer + @height, # BOTTOM RIGHT
window.width / 2 - @width / 2 + @slant, @spacer + @height, # BOTTOM LEFT
@shield
)
end
def update
percentage = "#{(@health * 100).round}".rjust(3, "0")
@text.text = "[Health #{percentage}%]"
@text.x = window.width / 2 - @text.width / 2
@text.y = @spacer + @height / 2 - @text.height / 2
@health += 0.1 * window.dt
@health = 0 if @health > 1.0
end
end
end
end

28
lib/hud/widgets/radar.rb Normal file
View File

@@ -0,0 +1,28 @@
class IMICFPS
class HUD
class RadarWidget < HUD::Widget
def setup
@size = 256
@color = Gosu::Color.new(0x88222222)
@text = Text.new("RADAR")
end
def draw
Gosu.draw_rect(
@margin, window.height - (@size + @margin),
@size, @size,
@color
)
@text.draw
end
def update
@text.text = "RADAR: X #{@player.position.x.round(1)} Y #{@player.position.z.round(1)}"
@text.x = @margin + @size / 2 - @text.width / 2
@text.y = window.height - (@margin + @size)
end
end
end
end

View File

@@ -0,0 +1,26 @@
class IMICFPS
class NetworkManager
MULTICAST_ADDRESS = "224.0.0.1"
MULTICAST_PORT = 30_000
REMOTE_GAMEHUB = "i-mic.rubyclan.org"
REMOTE_GAMEHUB_PORT = 98765
DEFAULT_SERVER_HOST = "0.0.0.0"
DEFAULT_SERVER_PORT = 56789
DEFAULT_SERVER_QUERY_PORT = 28900
def initialize
end
# https://github.com/jpignata/blog/blob/master/articles/multicast-in-ruby.md
def broadcast_lan_lobby
socket = UDPSocket.open
socket.setsockopt(:IPPROTO_IP, :IP_MULTICAST_TTL, 1)
socket.send("IMICFPS_LAN_LOBBY", 0, MULTICAST_ADDRESS, MULTICAST_PORT)
socket.close
end
def handle_lan_multicast
end
end
end

View File

@@ -14,7 +14,6 @@ class IMICFPS
@lights = []
@collision_manager = CollisionManager.new(map: self)
@renderer = window.renderer
Publisher.new
end
@@ -33,8 +32,11 @@ class IMICFPS
add_entity(Player.new(spawnpoint: @map_parser.spawnpoints.sample, manifest: Manifest.new(package: "base", name: "character")))
# add_light(Light.new(id: available_light, position: Vector.new(30, 10.0, 30)))
# add_light(Light.new(id: available_light, position: Vector.new(0, 100, 0), diffuse: Color.new(1.0, 0.5, 0.1)))
# Default lights if non are defined
if @map_parser.lights.size == 0
add_light(Light.new(id: available_light, position: Vector.new(30, 10.0, 30)))
add_light(Light.new(id: available_light, position: Vector.new(0, 100, 0), diffuse: Color.new(1.0, 0.5, 0.1)))
end
end
def data
@@ -51,7 +53,7 @@ class IMICFPS
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # clear the screen and the depth buffer
gl_error?
@renderer.draw(camera, @lights, @entities)
window.renderer.draw(camera, @lights, @entities)
end
end
@@ -59,7 +61,6 @@ class IMICFPS
@collision_manager.update
@entities.each(&:update)
# @lights.each(&:update)
end
end
end

View File

@@ -0,0 +1,6 @@
class IMICFPS
module Networking
class MemoryConnection < Connection
end
end
end

View File

@@ -0,0 +1,6 @@
class IMICFPS
module Networking
class MemoryServer < Server
end
end
end

18
lib/networking/client.rb Normal file
View File

@@ -0,0 +1,18 @@
class IMICFPS
module Networking
class Client
def initialize(socket:)
@socket = socket
end
def read
end
def write
end
def close
end
end
end
end

View File

@@ -0,0 +1,17 @@
class IMICFPS
module Networking
class Connection
def initialize(hostname:, port:)
end
def connect
end
def update
end
def close
end
end
end
end

View File

@@ -0,0 +1,61 @@
class IMICFPS
module Networking
class Director
attr_reader :mode, :hostname, :port, :tick_rate, :storage
def initialize(mode:, hostname:, port:, interface:, state: nil, tick_rate: 2)
@mode = mode
@hostname = hostname
@port = port
@state = state
@tick_rate = (1000.0 / tick_rate) / 1000.0
case @mode
when :server
@server = interface.new(hostname: @hostname, port: @port)
when :connection
@connection = interface.new(hostname: @hostname, port: @port)
when :memory
@server = interface[:server].new(hostname: @hostname, port: @port)
@connection = interface[:connection].new(hostname: @hostname, port: @port)
else
raise ArgumentError, "Expected mode to be :server, :connection, or :memory, not #{mode.inspect}"
end
@last_tick_time = milliseconds
@directing = true
@storage = {}
end
def run
Thread.start do |thread|
while(@directing)
dt = milliseconds - @last_tick_time
tick(dt)
@server.update if @server
@connection.update if @connection
@last_tick_time = milliseconds
sleep(@tick_rate)
end
end
end
def tick(dt)
end
def shutdown
@directing = false
@clients.each(&:close)
@server.update if @server
@connection.update if @connection
end
def milliseconds
Process.clock_gettime(Process::CLOCK_MONOTONIC)
end
end
end
end

11
lib/networking/events.rb Normal file
View File

@@ -0,0 +1,11 @@
class IMICFPS
module Networking
module Events
def on_connect(client)
end
def on_disconnect(client)
end
end
end
end

18
lib/networking/packet.rb Normal file
View File

@@ -0,0 +1,18 @@
class IMICFPS
module Networking
class Packet
def initialize(type:, payload:)
end
def self.encode(packet)
"#{packet.type}|#{packet.payload}"
end
def self.decode(string)
split = string.split("|")
Packet.new(split.first, split.last)
end
end
end
end

View File

@@ -0,0 +1,6 @@
class IMICFPS
module Networking
class PacketHandler
end
end
end

29
lib/networking/server.rb Normal file
View File

@@ -0,0 +1,29 @@
class IMICFPS
module Networking
MAX_CLIENTS = 32
class Server
attr_reader :hostname, :port, :max_clients, :clients
def initialize(hostname:, port:, max_clients: MAX_CLIENTS)
@hostname = hostname
@port = port
@max_clients = max_clients
@clients = []
@socket = nil
end
def bind
end
def broadcast(packet)
end
def update
end
def close
end
end
end
end

59
lib/overlay.rb Normal file
View File

@@ -0,0 +1,59 @@
class IMICFPS
class Overlay
include CommonMethods
Slot = Struct.new(:value, :width)
def initialize
@text = CyberarmEngine::Text.new("", x: 3, y: 3, shadow_color: Gosu::Color::BLACK)
@slots = []
@space_width = @text.textobject.text_width(" ")
end
def draw
return if @text.text.empty?
width = @text.width + 8
Gosu.draw_rect(0, 0, width, (@text.height + 4), Gosu::Color.rgba(0, 0, 0, 100))
Gosu.draw_rect(2, 2, width - 4, (@text.height + 4) - 4, Gosu::Color.rgba(100, 100, 100, 100))
@text.draw
end
def update
rebuild_slots
end
def rebuild_slots
@slots.clear
if window.config.get(:options, :fps)
create_slot "FPS: #{Gosu.fps}"
create_slot "Frame time: #{Gosu.milliseconds - window.delta_time}ms" if window.config.get(:debug_options, :stats)
end
if window.config.get(:debug_options, :stats)
create_slot "Vertices: #{formatted_number(window.number_of_vertices)}"
create_slot "Faces: #{formatted_number(window.number_of_vertices / 3)}"
end
if window.config.get(:debug_options, :boundingboxes)
create_slot "Boundingboxes: #{window.config.get(:debug_options, :boundingboxes) ? 'On' : 'Off'}"
end
if window.config.get(:debug_options, :wireframe)
create_slot "Wireframes: #{window.config.get(:debug_options, :wireframe) ? 'On' : 'Off'}"
end
@text.text = ""
@slots.each_with_index do |slot, i|
@text.text += "#{slot.value} <c=ff000000>•</c> " unless i == @slots.size - 1
@text.text += "#{slot.value}" if i == @slots.size - 1
end
end
def create_slot(string)
@slots << Slot.new(string, @text.textobject.text_width(string))
end
end
end

View File

@@ -16,7 +16,7 @@ class IMICFPS
end
def render(camera, lights, entities)
if Shader.available?("default") && Shader.available?("render_screen")
if window.config.get(:debug_options, :use_shaders) && Shader.available?("default") && Shader.available?("render_screen")
@g_buffer.bind_for_writing
gl_error?
@@ -155,6 +155,7 @@ class IMICFPS
end
if window.config.get(:debug_options, :wireframe)
glLineWidth(2)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
Shader.active_shader.uniform_boolean("disableLighting", true)
@@ -163,6 +164,7 @@ class IMICFPS
Shader.active_shader.uniform_boolean("disableLighting", false)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
glLineWidth(1)
end
glDrawArrays(GL_TRIANGLES, 0, model.faces.count * 3)

View File

@@ -0,0 +1,53 @@
class IMICFPS
class Boot < GameState
def setup
@title = Text.new(IMICFPS::NAME, size: 100, z: 0, color: Gosu::Color.new(0xff000000), shadow: false, font: "Droid Serif")
@logo = get_image(IMICFPS::GAME_ROOT_PATH + "/static/logo.png")
@start_time = Gosu.milliseconds
@time_to_live = 3_000
window.needs_cursor = false
end
def draw
fraction_left = ((Gosu.milliseconds - @start_time) / (@time_to_live - 200).to_f)
menu_background(Menu::PRIMARY_COLOR, Menu::ACCENT_COLOR, Menu::BAR_COLOR_STEP, Menu::BAR_ALPHA, Menu::BAR_SIZE, Menu::BAR_SLOPE)
if fraction_left <= 1.0
Gosu.draw_circle(
window.width / 2,
window.height / 2,
@logo.width / 2, 128, Gosu::Color.new(0x11ffffff)
)
Gosu.draw_arc(
window.width / 2,
window.height / 2,
@logo.width / 2, fraction_left.clamp(0.0, 1.0), 128, 8, Gosu::Color.new(0x33ff8800)
)
@logo.draw(window.width / 2 - @logo.width / 2, window.height / 2 - @logo.height / 2, 0)
@title.draw
end
end
def update
@title.x = window.width / 2 - @title.width / 2
@title.y = 0
push_state(MainMenu) if Gosu.milliseconds - @start_time >= @time_to_live
end
def button_up(id)
if id == Gosu::KbEscape or
(id >= Gosu::GP_LEFT and id >= Gosu::GP_BUTTON_15) or
id == Gosu::MsLeft
push_state(MainMenu)
end
end
end
end

View File

@@ -0,0 +1,49 @@
class IMICFPS
class Close < GameState
def setup
@slope = Menu::BAR_SLOPE
@logo = get_image(IMICFPS::GAME_ROOT_PATH + "/static/logo.png")
@start_time = Gosu.milliseconds
@time_to_live = 3_000
window.needs_cursor = false
end
def draw
fraction_left = 1 - ((Gosu.milliseconds - @start_time) / (@time_to_live - 200).to_f)
menu_background(Menu::PRIMARY_COLOR, Menu::ACCENT_COLOR, Menu::BAR_COLOR_STEP, Menu::BAR_ALPHA, Menu::BAR_SIZE, @slope.round)
Gosu.draw_circle(
window.width / 2,
window.height / 2,
@logo.width / 2, 128, Gosu::Color.new(0x11ffffff)
)
Gosu.draw_arc(
window.width / 2,
window.height / 2,
@logo.width / 2, fraction_left.clamp(0.0, 1.0), 128, 8, Gosu::Color.new(0x33ff8800)
)
@logo.draw(window.width / 2 - @logo.width / 2, window.height / 2 - @logo.height / 2, 0)
fill(Gosu::Color.rgba(0,0,0, 255 * (1.1 - fraction_left)))
end
def update
window.close! if Gosu.milliseconds - @start_time >= @time_to_live
@slope -= 25 * window.dt
end
def button_up(id)
if id == Gosu::KbEscape or
(id >= Gosu::GP_LEFT and id >= Gosu::GP_BUTTON_15) or
id == Gosu::MsLeft
window.close!
end
end
end
end

View File

@@ -9,10 +9,12 @@ class IMICFPS
@player = @map.find_entity_by(name: "character")
@camera = Camera.new(position: @player.position.clone)
@camera.attach_to(@player)
@director = Networking::Director.new(mode: :memory, hostname: "i-mic.rubyclan.org", port: 56789, interface: { server: Networking::MemoryServer, connection: Networking::MemoryConnection }, state: self)
@crosshair = Crosshair.new
@hud = HUD.new(@player)
@text = Text.new("Pending...", x: 10, y: 10, z: 1, size: 18, font: "DejaVu Sans", shadow_color: Gosu::Color::BLACK)
@text = Text.new("Pending...", x: 10, y: 22, z: 1, size: 18, font: "DejaVu Sans", shadow_color: Gosu::Color::BLACK)
if ARGV.join.include?("--playdemo")
@demo = Demo.new(camera: @camera, player: @player, demo: "./demo.dat", mode: :play) if File.exist?("./demo.dat")
@@ -26,6 +28,7 @@ class IMICFPS
@map.render(@camera)
@crosshair.draw
@hud.draw
@text.draw
end
@@ -37,20 +40,18 @@ class IMICFPS
@map.update
control_player
@hud.update
@camera.update
@director.tick(window.dt)
if window.config.get(:debug_options, :stats)
@text.text = update_text
elsif window.config.get(:options, :fps)
@text.text = "FPS: #{Gosu.fps}"
else
@text.text = ""
end
@demo.update if @demo
window.number_of_vertices = 0
end
def update_text
@@ -66,10 +67,6 @@ Camera Field Of View: #{@camera.field_of_view}
Camera Mouse Sesitivity: #{@camera.mouse_sensitivity}
#{if @camera.entity then "Actor X: #{@camera.entity.position.x.round(2)} Y: #{@camera.entity.position.y.round(2)} Z: #{@camera.entity.position.z.round(2)}";end}
Last Frame: #{Gosu.milliseconds - window.delta_time}ms (#{Gosu.fps} fps)
Vertices: #{formatted_number(window.number_of_vertices)}
Faces: #{formatted_number(window.number_of_vertices/3)}
eos
end

View File

@@ -2,9 +2,15 @@ class IMICFPS
class LoadingState < Menu
def setup
window.needs_cursor = false
if @options[:map_file]
@map_parser = MapParser.new(map_file: @options[:map_file])
elsif @options[:map_parser]
@map_parser = @options[:map_parser]
else
raise "Unable to load map, missing :map_file or :map_parser"
end
title "I-MIC FPS"
title IMICFPS::NAME
@subheading = Text.new("Loading Map: #{@map_parser.metadata.name}", y: 100, size: 50, alignment: :center)
@description = Text.new("Map created by: #{@map_parser.metadata.authors.join(", ")}\n#{@map_parser.metadata.description}", y: 180, size: 24, alignment: :center)
@state = Text.new("Preparing...", y: window.height/2-40, size: 40, alignment: :center)
@@ -28,7 +34,8 @@ class IMICFPS
@completed_for_ms = 0
@lock = false
@base_color = Gosu::Color.rgb(0, 180, 180)
@primary_color = Gosu::Color.rgba(0, 180, 180, 200)
@accent_color = Gosu::Color.rgba(0, 90, 90, 200)
end
def draw
@@ -109,9 +116,9 @@ class IMICFPS
progress = (@asset_index.to_f/@assets.count)*window.width/2
height = 100
dark_color= Gosu::Color.rgb(@base_color.red - 100, @base_color.green - 100, @base_color.blue - 100)#Gosu::Color.rgb(64, 127, 255)
color = Gosu::Color.rgb(@base_color.red - 50, @base_color.green - 50, @base_color.blue - 50)#Gosu::Color.rgb(0,127,127)
color_two = Gosu::Color.rgb(@base_color.red + 50, @base_color.green + 50, @base_color.blue + 50)#Gosu::Color.rgb(64, 127, 255)
dark_color= Gosu::Color.rgb(@primary_color.red - 100, @primary_color.green - 100, @primary_color.blue - 100)#Gosu::Color.rgb(64, 127, 255)
color = Gosu::Color.rgb(@primary_color.red - 50, @primary_color.green - 50, @primary_color.blue - 50)#Gosu::Color.rgb(0,127,127)
color_two = Gosu::Color.rgb(@primary_color.red + 50, @primary_color.green + 50, @primary_color.blue + 50)#Gosu::Color.rgb(64, 127, 255)
draw_rect(x, y-2, x + window.width/4, height+4, dark_color)

View File

@@ -1,12 +1,9 @@
class IMICFPS
class AssetViewerTool
class MainMenu < CyberarmEngine::GuiState
class MainMenu < Menu
def setup
window.needs_cursor = true
label "#{IMICFPS::NAME}", text_size: 50
label "Asset Viewer", text_size: 28
@manifests = []
Dir.glob(GAME_ROOT_PATH + "/assets/**/manifest.yaml").each do |manifest|
begin
@@ -18,11 +15,18 @@ class IMICFPS
@manifests.sort_by! { |m| m.name.downcase }
label "#{IMICFPS::NAME}", text_size: 100, color: Gosu::Color::BLACK
label "Asset Viewer", text_size: 50
flow(width: 1.0, height: 1.0) do
stack(width: 0.25, height: 1.0) do
button "Back", margin_bottom: 25 do
pop_state
end
end
flow(margin: 10) do
stack(width: 0.5, height: 1.0) do
flow(width: 1.0, height: 1.0) do
@manifests.each do |manifest|
button manifest.name do
push_state(TurnTable, manifest: manifest)
@@ -30,6 +34,8 @@ class IMICFPS
end
end
end
end
end
def update
super

View File

@@ -31,7 +31,6 @@ class IMICFPS
@lights << @light
@camera = Camera.new(position: Vector.new(0, 1.5, 5), orientation: Vector.forward)
@renderer = Renderer.new
label @manifest.name, text_size: 50
label @manifest.model
@@ -55,7 +54,7 @@ class IMICFPS
)
Gosu.gl do
@renderer.draw(@camera, [@light], @map.entities)
window.renderer.draw(@camera, [@light], @map.entities)
end
@crosshair.draw

View File

@@ -1 +1,2 @@
require_relative "map_editor/lib/main_menu"
require_relative "map_editor/lib/editor"

View File

@@ -0,0 +1,59 @@
class IMICFPS
class MapEditorTool
class Editor < CyberarmEngine::GuiState
attr_reader :map
def setup
# TODO: Move everything required for a playable game map
# in to a Scene or Scene3D container object
# and refactor Game to use it.
Publisher.new
@map = Map.new( map_parser: @options[:map_parser] )
@camera = Camera.new( position: Vector.new )
@crosshair = Crosshair.new
@map.setup
end
def draw
super
@map.render(@camera)
@crosshair.draw
end
def update
super
Publisher.instance.publish(:tick, Gosu.milliseconds - window.delta_time)
@map.update
@camera.update
end
def button_down(id)
if id == Gosu::KB_ESCAPE
# TODO: Use Editor specific menu
push_state(GamePauseMenu)
return
end
InputMapper.keydown(id)
Publisher.instance.publish(:button_down, nil, id)
@map.entities.each do |entity|
entity.button_down(id) if defined?(entity.button_down)
end
end
def button_up(id)
InputMapper.keyup(id)
Publisher.instance.publish(:button_up, nil, id)
@map.entities.each do |entity|
entity.button_up(id) if defined?(entity.button_up)
end
@camera.button_up(id)
end
end
end
end

View File

@@ -1,6 +1,6 @@
class IMICFPS
class MapEditorTool
class MainMenu < CyberarmEngine::GuiState
class MainMenu < Menu
def setup
window.needs_cursor = true
@@ -29,7 +29,7 @@ class IMICFPS
flow(margin: 10) do
@maps.each do |map|
button map.metadata.name do
# push_state(TurnTable, manifest: manifest)
push_state(LoadingState, map_parser: map, forward: Editor)
end
end
end

View File

@@ -1,12 +1,23 @@
class IMICFPS
class Menu < IMICFPS::GameState
class Menu < IMICFPS::GuiState
include CommonMethods
PRIMARY_COLOR = Gosu::Color.rgba(255, 127, 0, 200)
ACCENT_COLOR = Gosu::Color.rgba(155, 27, 0, 200)
BAR_SIZE = 50
BAR_SLOPE = 250
BAR_COLOR_STEP = 10
BAR_ALPHA = 200
def initialize(*args)
@elements = []
@size = 50
@slope = 250
@color_step = 10
@base_color = Gosu::Color.rgb(255, 127, 0)
@background_alpha = 200
@bar_size = BAR_SIZE
@bar_slope = BAR_SLOPE
@bar_color_step = BAR_COLOR_STEP
@bar_alpha = BAR_ALPHA
@primary_color = PRIMARY_COLOR
@accent_color = ACCENT_COLOR
window.needs_cursor = true
@__version_text = CyberarmEngine::Text.new("<b>#{IMICFPS::NAME}</b> v#{IMICFPS::VERSION} (#{IMICFPS::RELEASE_NAME})")
@@ -15,7 +26,7 @@ class IMICFPS
super(*args)
end
def title(text, color = @base_color)
def title(text, color = Gosu::Color::BLACK)
@elements << Text.new(text, color: color, size: 100, x: 0, y: 15)
@_title = @elements.last
end
@@ -31,7 +42,7 @@ class IMICFPS
end
def draw
draw_background
menu_background(@primary_color, @accent_color, @bar_color_step, @bar_alpha, @bar_size, @bar_slope)
draw_menu_box
draw_menu
@@ -44,34 +55,15 @@ class IMICFPS
window.scene.draw
end
end
def draw_background
((Gosu.screen_height+@slope)/@size).times do |i|
fill_quad(
0, i*@size,
0, @slope+(i*@size),
window.width/2, (-@slope)+(i*@size),
window.width/2, i*@size,
Gosu::Color.rgba(@base_color.red-i*@color_step, @base_color.green-i*@color_step, @base_color.blue-i*@color_step, @background_alpha),
-2
)
fill_quad(
window.width, i*@size,
window.width, @slope+(i*@size),
window.width/2, (-@slope)+(i*@size),
window.width/2, i*@size,
Gosu::Color.rgba(@base_color.red-i*@color_step, @base_color.green-i*@color_step, @base_color.blue-i*@color_step, @background_alpha),
-2
)
end
super
end
def draw_menu_box
draw_rect(
window.width / 4, 0,
window.width / 2, window.height,
Gosu::Color.rgba(0, 0, 0, 150),
Gosu::Color.new(0x11ffffff),
)
end
@@ -83,7 +75,7 @@ class IMICFPS
def update
@elements.each do |e|
e.x = window.width / 2 - e.width / 2
e.x = (window.width / 2 - e.width / 2).round
e.update
end
@@ -91,20 +83,12 @@ class IMICFPS
window.scene.update(window.dt)
end
super
@__version_text.x = window.width - (@__version_text.width + 10)
@__version_text.y = window.height - (@__version_text.height + 10)
end
def fill_quad(x1, y1, x2, y2, x3, y3, x4, y4, color = Gosu::Color::WHITE, z = 0, mode = :default)
draw_quad(
x1,y1, color,
x2,y2, color,
x3,y3, color,
x4,y4, color,
z, mode
)
end
def button_up(id)
if id == Gosu::MsLeft
@elements.each do |e|
@@ -114,6 +98,8 @@ class IMICFPS
end
end
end
super
end
def mouse_over?(object)
@@ -126,19 +112,17 @@ class IMICFPS
def initialize(text, host, block)
@text, @host, @block = text, host, block
@color = @text.color
@hover_color = Gosu::Color.rgb(64, 127, 255)
@hover_color = Gosu::Color.rgb(64, 128, 255)
@text.shadow_color= Gosu::Color::BLACK
@text.shadow_size = 2
@text.shadow_alpha = 100
end
def update
if @host.mouse_over?(self)
@text.color = @hover_color
@text.shadow_color= Gosu::Color::BLACK
@text.shadow_size = 3
else
@text.color = @color
@text.shadow_color = nil
@text.shadow_size = 1
end
end

View File

@@ -1,7 +1,7 @@
class IMICFPS
class ExtrasMenu < Menu
def setup
title "I-MIC FPS"
title IMICFPS::NAME
subtitle "Extras"
link "Asset Viewer" do

View File

@@ -1,8 +1,8 @@
class IMICFPS
class GamePauseMenu < Menu
def setup
@background_alpha = 50
title "I-MIC FPS"
@bar_alpha = 50
title IMICFPS::NAME
subtitle "Paused"
link "Resume" do
@@ -13,7 +13,7 @@ class IMICFPS
push_state(SettingsMenu)
end
link "Quit" do
link "Leave" do
push_state(MainMenu)
end
end

View File

@@ -1,7 +1,7 @@
class IMICFPS
class LevelSelectMenu < Menu
def setup
title "I-MIC FPS"
title IMICFPS::NAME
subtitle "Choose a Map"
Dir.glob(GAME_ROOT_PATH + "/maps/*.json").map { |file| [file, MapParser.new(map_file: file)]}.each do |file, map|

View File

@@ -1,13 +1,17 @@
class IMICFPS
class MainMenu < Menu
def setup
title "I-MIC FPS"
title IMICFPS::NAME
link "Single Player" do
push_state(LevelSelectMenu)
# push_state(LoadingState.new(forward: Game, map_file: GAME_ROOT_PATH + "/maps/test_map.json"))
end
link "Multiplayer" do
push_state(MultiplayerMenu)
end
link "Settings" do
push_state(SettingsMenu)
end
@@ -16,7 +20,7 @@ class IMICFPS
push_state(ExtrasMenu)
end
link "Exit" do
link "Exit Game" do
window.close
end

View File

@@ -0,0 +1,14 @@
class IMICFPS
class MultiplayerMenu < Menu
def setup
title IMICFPS::NAME
subtitle "Multiplayer"
link "Online"
link "LAN"
link "Back" do
pop_state
end
end
end
end

View File

@@ -1,14 +1,208 @@
class IMICFPS
class SettingsMenu < Menu
include CommonMethods
def setup
title "I-MIC FPS"
subtitle "Settings"
@categories = [
"Display",
"Graphics",
"Audio",
"Controls",
"Multiplayer"
]
@pages = {}
@current_page = nil
link "\"There is no spoon.\""
label "Settings", text_size: 100, color: Gosu::Color::BLACK
link "Back" do
flow(width: 1.0, height: 1.0) do
stack(width: 0.25, height: 1.0) do
@categories.each do |category|
button category, width: 1.0 do
show_page(:"#{category}".downcase)
end
end
button "Back", width: 1.0, margin_top: 64 do
pop_state
end
end
@categories.each do |category|
stack(width: 0.5, height: 1.0) do |element|
@pages[:"#{category}".downcase] = element
element.hide
if respond_to?(:"create_page_#{category}".downcase)
self.send(:"create_page_#{category}".downcase)
end
end
end
end
show_page(:display)
end
def show_page(page)
if element = @pages.dig(page)
@current_page.hide if @current_page
@current_page = element
element.show
end
end
def create_page_display
label "Display", text_size: 50
label "Resolution"
flow do
stack do
label "Width"
label "Height"
end
stack do
edit_line "#{window.width}"
edit_line "#{window.height}"
end
end
check_box "Fullscreen", padding_top: 25, padding_bottom: 25
flow do
stack do
label "Gamma Correction"
label "Brightness"
label "Contrast"
end
stack do
slider
slider
slider
end
stack do
label "0.0"
label "0.0"
label "0.0"
end
end
end
def create_page_audio
label "Audio", text_size: 50
flow do
stack do
label "Master Volume"
label "Sound Effects"
label "Dialog"
label "Cinematic"
end
stack do
slider range: 0.0..1.0, value: 1.0
slider range: 0.0..1.0, value: 1.0
slider range: 0.0..1.0, value: 1.0
slider range: 0.0..1.0, value: 1.0
end
stack do
label "0.0"
label "0.0"
label "0.0"
label "0.0"
end
end
end
def create_page_controls
label "Controls", text_size: 50
InputMapper.keymap.each do |key, values|
flow do
label "#{key}"
[values].flatten.each do |value|
button Gosu.button_id_to_char(value)
end
end
end
end
def create_page_graphics
label "Graphics", text_size: 50
flow do
check_box "V-Sync"
label "(No Supported)"
end
flow do
label "Field of View"
slider range: 70.0..110.0
label "90.0"
end
flow do
stack do
label "Detail"
end
stack do
slider range: 1..3
end
stack do
label "High"
end
end
advanced_mode = check_box "Advanced Mode"
advanced_settings = stack do |element|
element.hide
flow do
stack do
label "Geometry Detail"
label "Shadow Detail"
label "Texture Detail"
label "Particle Detail"
label "Surface Effect Detail"
end
stack do
slider
slider
slider
slider
slider
end
stack do
label "High"
label "High"
label "High"
label "High"
label "High"
end
end
flow do
stack do
label "Lighting Mode"
edit_line ""
end
stack do
label "Texture Filtering"
edit_line ""
end
end
end
advanced_mode.subscribe(:changed) do |element, value|
advanced_settings.show if value
advanced_settings.hide unless value
end
end
def create_page_multiplayer
label "Multiplayer", text_size: 50
check_box "Show player names"
end
end
end

View File

@@ -1,5 +1,5 @@
class IMICFPS
class Window < CyberarmEngine::Engine
class Window < CyberarmEngine::Window
attr_accessor :number_of_vertices, :needs_cursor
attr_reader :renderer, :scene, :config
@@ -26,6 +26,7 @@ class IMICFPS
@renderer = Renderer.new
@renderer.preload_default_shaders
@scene = TurnTableScene.new
@overlay = Overlay.new
@canvas_size = Vector.new(self.width, self.height)
@@ -33,7 +34,7 @@ class IMICFPS
@config.save!
end
push_state(MainMenu)
push_state(Boot)
@delta_time = Gosu.milliseconds
end
@@ -46,6 +47,7 @@ class IMICFPS
super
@console.draw if @show_console
@overlay.draw
draw_cursor if needs_cursor
_canvas_size = Vector.new(self.width, self.height)
@@ -65,9 +67,16 @@ class IMICFPS
super
@console.update if @show_console
@overlay.update
@number_of_vertices = 0
@delta_time = Gosu.milliseconds
end
def close
push_state(Close)
end
def button_down(id)
if @show_console
@console.button_down(id)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 B

166
rakelib/release.rake Normal file
View File

@@ -0,0 +1,166 @@
PACKAGING_LOCKFILE = File.expand_path("i-mic-fps-packaging.lock", Dir.tmpdir)
GITHUB_API_URL = "https://api.github.com/repos/cyberarm/i-mic-fps"
USERAGENT = "cyberarm +i-mic-fps"
DEFAULT_HEADERS = {"Authorization": "token #{ENV["GITHUB_TOKEN"]}", "User-Agent": USERAGENT}
def sh_with_status(command)
outbuf = IO.popen(command, :err => [:child, :out], &:read)
status = $?
return [outbuf, status]
end
def version
IMICFPS::VERSION
end
def version_tag
"v#{version}"
end
def release_name
"#{IMICFPS::NAME.gsub(" ", "-").downcase}_#{version_tag}"
end
def clean?
sh_with_status("git diff --exit-code")[1].success?
end
def committed?
sh_with_status("git diff-index --quiet --cached HEAD")[1].success?
end
def guard_clean
clean? && committed? || abort(" There are files that need to be committed.")
end
def tag_version
sh "git tag -m \"Version #{version}\" #{version_tag}"
puts " Tagged #{version_tag}."
rescue RuntimeError
puts " Untagging #{version_tag} due to error."
sh_with_status "git tag -d #{version_tag}"
abort
end
def already_tagged?
return false unless sh_with_status("git tag")[0].split(/\n/).include?(version_tag)
abort " Tag #{version_tag} has already been created."
end
def create_lockfile
File.open(PACKAGING_LOCKFILE, "w") { |f| f.write version }
end
def remove_lockfile
File.delete(PACKAGING_LOCKFILE)
rescue Errno::ENOENT
end
def create_directory(dir)
levels = dir.split("/")
location = ""
levels.each do |level|
location +="#{level}/"
mkdir_p location unless File.exist?(location)
end
end
def build_package(path)
abort " Package folder already exists!" if File.exist?(path)
sh "rake build:windows:folder"
end
def patch_windows_package(folder)
patch = "require_relative \"i-mic-fps/i-mic-fps\""
patch_file = "#{folder}/src/i-mic-fps.rb"
File.open(patch_file, "w") { |f| f.write patch }
end
def create_archive(folder, archive)
abort " Archive already exists!" if File.exist?(archive)
Zip::File.open(archive, Zip::File::CREATE) do |zipfile|
Dir["#{folder}/**/**"].each do |file|
zipfile.add(file.sub(folder + '/', ''), file)
end
end
end
def get_release
url = "#{GITHUB_API_URL}/releases"
request = Excon.get(url, headers: DEFAULT_HEADERS)
if request.status == 200
release = JSON.parse(request.body).find { |r| r["tag_name"] == version_tag }
return release
else
abort " Getting repo releases failed! (#{request.status})"
end
end
def upload_asset(asset)
github_token = ENV["GITHUB_TOKEN"]
abort " GITHUB_TOKEN not set!" unless github_token
release = get_release
upload_url = release["upload_url"].split("{?").first + "?name=#{asset.split("/").last}"
file = File.read(asset)
headers = DEFAULT_HEADERS
headers["Content-Type"] = "application/zip"
headers["Content-Length"] = file.size
request = Excon.post(upload_url, body: file, headers: headers)
abort " Upload failed! #{request.body} (#{request.status})" unless request.status.between?(200, 201)
end
namespace "game" do
desc "Create git tag, build, and release package"
task :release do
puts "Checking for uncommited changes..."
guard_clean
puts "Checking git tag for #{version_tag}..."
already_tagged?
puts "Committing git tag #{version_tag}..."
tag_version
puts "Pushing changes..."
sh "git push origin master"
sh "git push origin master --tags"
path = File.expand_path("../pkg/#{release_name}_WIN32", __dir__)
puts "Building release package '#{release_name}', this may take a while..."
create_lockfile
build_package(path)
puts "Patching..."
patch_windows_package(path)
puts "Creating archive..."
create_archive(path, "#{path}.zip")
remove_lockfile
puts "Pushing package to github..."
upload_asset("#{path}.zip")
puts "Done."
end
desc "Remove packaging assets"
task "release:cleanup" do
path = File.expand_path("../pkg", __dir__)
if File.exist?(path)
puts "Cleaning up..."
Dir["#{path}/**"].each do |file|
puts "Removing #{file}..."
if File.directory?(file)
FileUtils.remove_entry_secure(file)
else
File.delete(file)
end
end
puts "Done."
end
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
static/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

128
svg/logo.svg Normal file
View File

@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="232"
height="232"
viewBox="0 0 61.383334 61.383334"
version="1.1"
id="svg8"
sodipodi:docname="logo.svg"
inkscape:export-filename="/home/cyberarm/Code/i-mic-fps/static/logo.png"
inkscape:export-xdpi="211.86208"
inkscape:export-ydpi="211.86208"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="28.822764"
inkscape:cy="101.19387"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:snap-bbox="true"
inkscape:snap-intersection-paths="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1010"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid10"
empspacing="8"
originx="0"
originy="2.2411203e-09"
dotted="false" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-33.940008,-296.21455)">
<path
style="opacity:1;fill:#e9b96e;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
d="m 69.448977,318.17079 h -9.524999 l 4.7625,4.7625 z"
id="path42"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#8f5902;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
d="m 51.986478,310.23329 7.9375,7.9375 h 9.524999 l 7.9375,-7.9375 z"
id="path30"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#ce5c00;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
d="m 69.448977,318.17079 16.485815,16.48581 7.9375,-7.9375 -16.485815,-16.48581 z"
id="path47"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#ce5c00;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
d="m 64.686478,322.93329 v 32.97163 L 85.934792,334.6566 69.448977,318.17079 Z"
id="path50"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#f57900;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
d="M 59.923978,318.17079 43.438163,334.6566 64.686478,355.90492 V 322.93329 Z"
id="path45"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#f57900;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
d="m 51.986478,310.23329 -16.485815,16.48581 7.9375,7.9375 16.485815,-16.48581 z"
id="path28"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#f57900;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
d="m 64.686478,297.53329 -12.7,12.7 h 12.7 z"
id="path53"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#ce5c00;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
d="m 64.686478,297.53329 v 12.7 h 12.699999 z"
id="rect22"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="99.88446"
y="329.00253"
id="text14"><tspan
sodipodi:role="line"
id="tspan12"
x="99.88446"
y="329.00253"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Droid Serif';-inkscape-font-specification:'Droid Serif';fill:#000000;stroke-width:0.26458332">I-MIC FPS</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB