mirror of
https://github.com/cyberarm/i-mic-rts.git
synced 2025-12-15 07:42:34 +00:00
Inital work on gamesaves/replays
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
data/settings.json
|
data/settings.json
|
||||||
data/replays/*.replay
|
data/replays/*.dat
|
||||||
data/saves/*.save
|
data/saves/*.dat
|
||||||
doc/
|
doc/
|
||||||
.yardoc/
|
.yardoc/
|
||||||
@@ -8,6 +8,7 @@ end
|
|||||||
|
|
||||||
require "json"
|
require "json"
|
||||||
require "socket"
|
require "socket"
|
||||||
|
require "digest/sha2"
|
||||||
|
|
||||||
require "nokogiri"
|
require "nokogiri"
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ require_relative "lib/camera"
|
|||||||
require_relative "lib/setting"
|
require_relative "lib/setting"
|
||||||
require_relative "lib/team_colors"
|
require_relative "lib/team_colors"
|
||||||
require_relative "lib/constants"
|
require_relative "lib/constants"
|
||||||
|
require_relative "lib/game_save"
|
||||||
|
|
||||||
require_relative "lib/states/boot"
|
require_relative "lib/states/boot"
|
||||||
require_relative "lib/states/game"
|
require_relative "lib/states/game"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ class IMICRTS
|
|||||||
class Director
|
class Director
|
||||||
attr_reader :current_tick, :map, :game, :players
|
attr_reader :current_tick, :map, :game, :players
|
||||||
|
|
||||||
def initialize(game:, map:, players: [], networking_mode:, tick_rate: 10, local_game: true, replay: false)
|
def initialize(game:, map:, players:, networking_mode:, tick_rate: 15, local_game: true, replay: false, game_save: false, gamesave_file: nil)
|
||||||
@game = game
|
@game = game
|
||||||
@map = map
|
@map = map
|
||||||
@players = players
|
@players = players
|
||||||
@@ -11,6 +11,10 @@ class IMICRTS
|
|||||||
@tick_rate = tick_rate
|
@tick_rate = tick_rate
|
||||||
@local_game = local_game
|
@local_game = local_game
|
||||||
@replay = replay
|
@replay = replay
|
||||||
|
@game_save = game_save
|
||||||
|
@gamesave_file = gamesave_file ? gamesave_file : "#{IMICRTS::GAME_ROOT_PATH}/data/saves/savegame_#{Time.now.to_i}.dat"
|
||||||
|
@game_save_host = GameSave.new(mode: :write, gamesave_file: @gamesave_file, players: players, map_file: @map.map_file, gamesave: true)
|
||||||
|
@game_save_host.write_header
|
||||||
|
|
||||||
@last_tick_at = Gosu.milliseconds
|
@last_tick_at = Gosu.milliseconds
|
||||||
@tick_time = 1000.0 / @tick_rate
|
@tick_time = 1000.0 / @tick_rate
|
||||||
@@ -25,8 +29,8 @@ class IMICRTS
|
|||||||
@replay
|
@replay
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_player(player)
|
def game_save?
|
||||||
@players << player
|
@game_save
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@@ -35,6 +39,7 @@ class IMICRTS
|
|||||||
|
|
||||||
tick
|
tick
|
||||||
@connection.update
|
@connection.update
|
||||||
|
@game_save_host&.feed_tick(@current_tick) if @replay
|
||||||
end
|
end
|
||||||
|
|
||||||
@players.each { |player| player.update }
|
@players.each { |player| player.update }
|
||||||
@@ -58,6 +63,7 @@ class IMICRTS
|
|||||||
order_args = o.deserialize(order_data[1..order_data.length - 1], self)
|
order_args = o.deserialize(order_data[1..order_data.length - 1], self)
|
||||||
|
|
||||||
execute_order(o.id, *order_args)
|
execute_order(o.id, *order_args)
|
||||||
|
@game_save_host&.write_order(order_data) unless @replay
|
||||||
|
|
||||||
player.orders.delete(order)
|
player.orders.delete(order)
|
||||||
|
|
||||||
@@ -140,6 +146,7 @@ class IMICRTS
|
|||||||
def finalize
|
def finalize
|
||||||
@server&.stop
|
@server&.stop
|
||||||
@connection&.finalize
|
@connection&.finalize
|
||||||
|
@game_save_host&.finalize
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
50
lib/game_save.rb
Normal file
50
lib/game_save.rb
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
class IMICRTS
|
||||||
|
class GameSave
|
||||||
|
def initialize(mode:, gamesave_file:, map_file: nil, players: nil, gamesave: false, player_id: nil)
|
||||||
|
@mode = mode
|
||||||
|
@gamesave_file = File.open(gamesave_file, "#{@mode == :write ? 'w' : 'r'}")
|
||||||
|
@map_file = map_file
|
||||||
|
@players = players
|
||||||
|
@gamesave = gamesave
|
||||||
|
@player_id = player_id
|
||||||
|
|
||||||
|
@version = IMICRTS::VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse
|
||||||
|
#
|
||||||
|
end
|
||||||
|
|
||||||
|
def feed_tick(tick_id)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_header
|
||||||
|
player_data = @players.map do |player|
|
||||||
|
{
|
||||||
|
id: player.id,
|
||||||
|
name: player.name,
|
||||||
|
team: player.team,
|
||||||
|
spawnpoint: player.spawnpoint,
|
||||||
|
color: player.color&.gl,
|
||||||
|
bot: player.bot
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
s = %{#{@version}
|
||||||
|
#{@map_file}?#{Digest::SHA256.digest(File.read("#{IMICRTS::GAME_ROOT_PATH}/assets/#{@map_file}"))}
|
||||||
|
#{@gamesave ? "GAMESAVE?#{@player_id}" : "REPLAY"}
|
||||||
|
#{JSON.dump(player_data)}}
|
||||||
|
|
||||||
|
@gamesave_file.puts(s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_order(raw_order)
|
||||||
|
@gamesave_file.puts(raw_order)
|
||||||
|
end
|
||||||
|
|
||||||
|
def finalize
|
||||||
|
@gamesave_file&.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
class IMICRTS
|
class IMICRTS
|
||||||
class Map
|
class Map
|
||||||
attr_reader :tile_size, :tiles, :ores, :spawnpoints, :width, :height
|
attr_reader :tile_size, :tiles, :ores, :spawnpoints, :width, :height, :map_file
|
||||||
|
|
||||||
def initialize(map_file:)
|
def initialize(map_file:)
|
||||||
|
@map_file = map_file
|
||||||
@tiled_map = TiledMap.new(map_file)
|
@tiled_map = TiledMap.new(map_file)
|
||||||
|
|
||||||
@width = @tiled_map.width
|
@width = @tiled_map.width
|
||||||
|
|||||||
@@ -11,24 +11,26 @@ class IMICRTS
|
|||||||
@options[:map] ||= Map.new(map_file: "maps/test_map.tmx")
|
@options[:map] ||= Map.new(map_file: "maps/test_map.tmx")
|
||||||
@options[:local_player_id] ||= 0
|
@options[:local_player_id] ||= 0
|
||||||
|
|
||||||
@director = Director.new(game: self, map: @options[:map], networking_mode: @options[:networking_mode])
|
|
||||||
@options[:players] ||= [
|
@options[:players] ||= [
|
||||||
{ id: 0, team: 1, spawnpoint: @director.map.spawnpoints.last, color: :orange, bot: false },
|
{ id: 0, name: "0xdeadbeef", team: 1, spawnpoint: "B", color: :orange, bot: false },
|
||||||
{ id: 1, team: 2, spawnpoint: @director.map.spawnpoints.first, color: :lightblue, bot: :brutal }
|
{ id: 1, name: "BrutalAI", team: 2, spawnpoint: "A", color: :lightblue, bot: :brutal }
|
||||||
]
|
]
|
||||||
|
|
||||||
@options[:players].each do |pl|
|
players = @options[:players].map do |pl|
|
||||||
player = nil
|
player = nil
|
||||||
visiblity_map = VisibilityMap.new(width: @director.map.width, height: @director.map.height, tile_size: @director.map.tile_size)
|
visiblity_map = VisibilityMap.new(width: @options[:map].width, height: @options[:map].height, tile_size: @options[:map].tile_size)
|
||||||
unless pl[:bot]
|
unless pl[:bot]
|
||||||
player = Player.new(id: pl[:id], spawnpoint: pl[:spawnpoint], team: pl[:team], color: TeamColors[pl[:color]], visiblity_map: visiblity_map)
|
player = Player.new(id: pl[:id], name: pl[:name], spawnpoint: pl[:spawnpoint], team: pl[:team], color: TeamColors[pl[:color]], visiblity_map: visiblity_map)
|
||||||
else
|
else
|
||||||
player = AIPlayer.new(id: pl[:id], spawnpoint: pl[:spawnpoint], team: pl[:team], color: TeamColors[pl[:color]], bot: pl[:bot], visiblity_map: visiblity_map)
|
player = AIPlayer.new(id: pl[:id], name: pl[:name], spawnpoint: pl[:spawnpoint], team: pl[:team], color: TeamColors[pl[:color]], bot: pl[:bot], visiblity_map: visiblity_map)
|
||||||
end
|
end
|
||||||
@player = player if player.id == @options[:local_player_id]
|
@player = player if player.id == @options[:local_player_id]
|
||||||
@director.add_player(player)
|
|
||||||
|
player
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@director = Director.new(game: self, players: players, map: @options[:map], networking_mode: @options[:networking_mode])
|
||||||
|
|
||||||
@selected_entities = []
|
@selected_entities = []
|
||||||
@tool = set_tool(:entity_controller)
|
@tool = set_tool(:entity_controller)
|
||||||
@overlays = []
|
@overlays = []
|
||||||
@@ -61,9 +63,11 @@ class IMICRTS
|
|||||||
end
|
end
|
||||||
|
|
||||||
@director.players.each do |player|
|
@director.players.each do |player|
|
||||||
|
spawnpoint = @director.map.spawnpoints[player.spawnpoint.bytes.first - 65]
|
||||||
|
|
||||||
construction_yard = @director.spawn_entity(
|
construction_yard = @director.spawn_entity(
|
||||||
player_id: player.id, name: :construction_yard,
|
player_id: player.id, name: :construction_yard,
|
||||||
position: CyberarmEngine::Vector.new(player.spawnpoint.x, player.spawnpoint.y, ZOrder::BUILDING)
|
position: CyberarmEngine::Vector.new(spawnpoint.x, spawnpoint.y, ZOrder::BUILDING)
|
||||||
)
|
)
|
||||||
construction_yard.component(:structure).data.construction_progress = Entity.get(construction_yard.name).build_steps
|
construction_yard.component(:structure).data.construction_progress = Entity.get(construction_yard.name).build_steps
|
||||||
construction_yard.component(:structure).data.construction_complete = true
|
construction_yard.component(:structure).data.construction_complete = true
|
||||||
@@ -77,7 +81,7 @@ class IMICRTS
|
|||||||
|
|
||||||
@director.spawn_entity(
|
@director.spawn_entity(
|
||||||
player_id: player.id, name: :construction_worker,
|
player_id: player.id, name: :construction_worker,
|
||||||
position: CyberarmEngine::Vector.new(player.spawnpoint.x - 64, player.spawnpoint.y + 64, ZOrder::GROUND_VEHICLE)
|
position: CyberarmEngine::Vector.new(construction_yard.position.x - 64, construction_yard.position.y + 64, ZOrder::GROUND_VEHICLE)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user