termworld 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +9 -3
- data/lib/termworld.rb +14 -4
- data/lib/termworld/cli.rb +46 -2
- data/lib/termworld/commands/account.rb +35 -0
- data/lib/termworld/commands/daemon_operator.rb +50 -0
- data/lib/termworld/commands/user.rb +41 -0
- data/lib/termworld/commands/user_action.rb +58 -0
- data/lib/termworld/config.rb +8 -0
- data/lib/termworld/credential.rb +34 -0
- data/lib/termworld/daemon.rb +55 -0
- data/lib/termworld/db.rb +12 -0
- data/lib/termworld/models/user.rb +127 -0
- data/lib/termworld/resources/chip.rb +41 -0
- data/lib/termworld/resources/maps/town.rb +37 -0
- data/lib/termworld/terminal/controller.rb +74 -0
- data/lib/termworld/utils/api_client.rb +35 -0
- data/lib/termworld/utils/color.rb +20 -0
- data/lib/termworld/utils/option_parser_wrapper.rb +27 -0
- data/lib/termworld/{constants/version.rb → version.rb} +1 -1
- data/termworld.gemspec +3 -1
- metadata +46 -5
- data/lib/termworld/db/db.rb +0 -10
- data/lib/termworld/db/user.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdd1aafdb9205075fd1e3a25f335a02236fe901e455e9e36d173b8354a0b33b9
|
4
|
+
data.tar.gz: d953f8661dded33034572c8f3eb3100e38a1f77875f40a00ab77fe25064e6952
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 340f46ae87eec7fbc9482e0349e19fd980440d37eaf2e528fc613eeb806245be1c92518319ea0254af7d85fdc1d32191894cdb9ca8933b85a55d66b18d793b9d
|
7
|
+
data.tar.gz: 87fac115ba3651b040bc986deb7c06488fcde6c6cdf07e2511cd472675379eca09497e380de94ebf2671f170e548aa96ab954635d9264557566c8447236114aa
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
termworld (0.
|
4
|
+
termworld (0.2.0)
|
5
|
+
httpclient
|
5
6
|
sequel
|
6
7
|
sqlite3
|
8
|
+
term_canvas (= 0.2.9)
|
7
9
|
thor
|
8
10
|
|
9
11
|
GEM
|
@@ -11,7 +13,9 @@ GEM
|
|
11
13
|
specs:
|
12
14
|
byebug (11.0.1)
|
13
15
|
coderay (1.1.2)
|
16
|
+
curses (1.3.1)
|
14
17
|
diff-lcs (1.3)
|
18
|
+
httpclient (2.8.3)
|
15
19
|
method_source (0.9.2)
|
16
20
|
pry (0.12.2)
|
17
21
|
coderay (~> 1.1.0)
|
@@ -24,17 +28,19 @@ GEM
|
|
24
28
|
rspec-core (~> 3.8.0)
|
25
29
|
rspec-expectations (~> 3.8.0)
|
26
30
|
rspec-mocks (~> 3.8.0)
|
27
|
-
rspec-core (3.8.
|
31
|
+
rspec-core (3.8.1)
|
28
32
|
rspec-support (~> 3.8.0)
|
29
33
|
rspec-expectations (3.8.4)
|
30
34
|
diff-lcs (>= 1.2.0, < 2.0)
|
31
35
|
rspec-support (~> 3.8.0)
|
32
|
-
rspec-mocks (3.8.
|
36
|
+
rspec-mocks (3.8.1)
|
33
37
|
diff-lcs (>= 1.2.0, < 2.0)
|
34
38
|
rspec-support (~> 3.8.0)
|
35
39
|
rspec-support (3.8.2)
|
36
40
|
sequel (5.21.0)
|
37
41
|
sqlite3 (1.4.1)
|
42
|
+
term_canvas (0.2.9)
|
43
|
+
curses
|
38
44
|
thor (0.20.3)
|
39
45
|
|
40
46
|
PLATFORMS
|
data/lib/termworld.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
|
-
require "thor"
|
2
1
|
require "sequel"
|
3
2
|
|
4
|
-
require "termworld/
|
5
|
-
require "termworld/
|
3
|
+
require "termworld/config"
|
4
|
+
require "termworld/utils/color"
|
5
|
+
require "termworld/utils/api_client"
|
6
6
|
require "termworld/cli"
|
7
|
+
require "termworld/daemon"
|
7
8
|
|
8
9
|
module Termworld
|
9
10
|
def self.start
|
10
|
-
|
11
|
+
setup_termworld_directory
|
12
|
+
$api_client = Utils::ApiClient.new
|
13
|
+
$db = Sequel.sqlite(Termworld::DATABASE_NAME) if Daemon.new.alive?
|
11
14
|
CLI.start
|
12
15
|
end
|
16
|
+
|
17
|
+
def self.setup_termworld_directory
|
18
|
+
directory = Termworld::HOME_DIRECTORY_NAME
|
19
|
+
Dir::chdir(Dir::home)
|
20
|
+
Dir::mkdir(directory) unless Dir::exists?(directory)
|
21
|
+
Dir::chdir(directory)
|
22
|
+
end
|
13
23
|
end
|
data/lib/termworld/cli.rb
CHANGED
@@ -1,9 +1,53 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
require "termworld/db"
|
5
|
+
require "termworld/commands/account"
|
6
|
+
require "termworld/commands/daemon_operator"
|
7
|
+
require "termworld/commands/user"
|
8
|
+
require "termworld/commands/user_action"
|
9
|
+
require "termworld/credential"
|
10
|
+
require "termworld/utils/option_parser_wrapper"
|
11
|
+
|
1
12
|
module Termworld
|
2
13
|
class CLI < Thor
|
3
14
|
|
4
|
-
desc "
|
15
|
+
desc "login", "Login"
|
16
|
+
def login
|
17
|
+
Commands::Account.login
|
18
|
+
end
|
19
|
+
desc "logout", "Logout"
|
20
|
+
def logout
|
21
|
+
Commands::Account.logout
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "start", "Start game client"
|
5
25
|
def start
|
6
|
-
|
26
|
+
Commands::DaemonOperator.start
|
27
|
+
end
|
28
|
+
desc "stop", "Stop game client"
|
29
|
+
def stop
|
30
|
+
Commands::DaemonOperator.stop
|
31
|
+
end
|
32
|
+
desc "status", "Check status"
|
33
|
+
def status
|
34
|
+
Commands::DaemonOperator.status
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "user [COMMAND] <options>", "User actions"
|
38
|
+
subcommand "user", Commands::User
|
39
|
+
|
40
|
+
def method_missing(method, *arg, &block)
|
41
|
+
_method = method.to_s.split(?:)
|
42
|
+
begin
|
43
|
+
action_class = Object.const_get("Termworld::Commands::#{_method[0].capitalize}Action")
|
44
|
+
rescue
|
45
|
+
puts Utils::Color.reden "#{_method[0]} command not found"
|
46
|
+
return
|
47
|
+
end
|
48
|
+
action = action_class.new(_method[1])
|
49
|
+
return puts Utils::Color.reden "Enter any commands" if arg.empty?
|
50
|
+
action.send(arg[0], arg[1..-1])
|
7
51
|
end
|
8
52
|
end
|
9
53
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Termworld
|
2
|
+
module Commands
|
3
|
+
class Account
|
4
|
+
class << self
|
5
|
+
def login
|
6
|
+
credential = Credential.new
|
7
|
+
return puts Utils::Color.reden "Already logged in" if credential.logged_in?
|
8
|
+
print "email: "
|
9
|
+
email = $stdin.gets.chomp
|
10
|
+
res = $api_client.call(:post, '/token', {email: email})
|
11
|
+
return puts Utils::Color.reden "Invalid email" if res.code != 200
|
12
|
+
puts Utils::Color.greenen "Sent token to your email, please input below"
|
13
|
+
print "token: "
|
14
|
+
token = $stdin.gets.chomp
|
15
|
+
res = $api_client.call(:post, '/login', {email: email, token: token})
|
16
|
+
return puts Utils::Color.reden "Invalid token" if res.code != 200
|
17
|
+
File.write(Termworld::CREDENTIAL_FILE_NAME, "#{email}\n#{token}")
|
18
|
+
puts Utils::Color.greenen "Login successed!"
|
19
|
+
end
|
20
|
+
|
21
|
+
def logout
|
22
|
+
credential = Credential.new
|
23
|
+
return puts Utils::Color.reden "Not logged in" unless credential.logged_in?
|
24
|
+
email, token = Credential.get_credential
|
25
|
+
res = $api_client.call(:post, '/logout', {email: email, token: token})
|
26
|
+
return puts Utils::Color.reden "Logout failed" if res.code != 200
|
27
|
+
daemon = Daemon.new(:logout)
|
28
|
+
daemon.stop if daemon.alive?
|
29
|
+
File.delete(Termworld::CREDENTIAL_FILE_NAME) if File.exists?(Termworld::CREDENTIAL_FILE_NAME)
|
30
|
+
puts Utils::Color.greenen "Logout successed!"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Termworld
|
2
|
+
module Commands
|
3
|
+
class DaemonOperator
|
4
|
+
class << self
|
5
|
+
def start
|
6
|
+
credential = Credential.new
|
7
|
+
return puts credential.error_message unless credential.logged_in?
|
8
|
+
daemon = Daemon.new(:start)
|
9
|
+
return puts daemon.error_message if daemon.error_message
|
10
|
+
daemon.prepare
|
11
|
+
puts Utils::Color.greenen "Started!"
|
12
|
+
daemon.run
|
13
|
+
|
14
|
+
loop do
|
15
|
+
break unless daemon.alive?
|
16
|
+
sleep 1
|
17
|
+
end
|
18
|
+
daemon.stop
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
credential = Credential.new
|
23
|
+
daemon = Daemon.new(:stop)
|
24
|
+
unless credential.logged_in?
|
25
|
+
daemon.stop
|
26
|
+
return puts credential.error_message
|
27
|
+
end
|
28
|
+
if daemon.error_message
|
29
|
+
daemon.delete_files
|
30
|
+
return puts daemon.error_message
|
31
|
+
end
|
32
|
+
daemon.stop
|
33
|
+
puts Utils::Color.greenen "Stopped!"
|
34
|
+
end
|
35
|
+
|
36
|
+
def status
|
37
|
+
credential = Credential.new
|
38
|
+
return puts credential.error_message unless credential.logged_in?
|
39
|
+
daemon = Daemon.new(:status)
|
40
|
+
return puts daemon.error_message if daemon.error_message
|
41
|
+
if daemon.alive?
|
42
|
+
puts Utils::Color.bluen "Running!"
|
43
|
+
else
|
44
|
+
puts Utils::Color.bluen "Not running."
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Termworld
|
2
|
+
module Commands
|
3
|
+
class User < Thor
|
4
|
+
|
5
|
+
desc "create", "Create user"
|
6
|
+
def create(*options)
|
7
|
+
option_parser = Utils::OptionParserWrapper.new([
|
8
|
+
{option: ['-n', '--name [VALUE]', 'User name'], key: :name},
|
9
|
+
])
|
10
|
+
params = option_parser.parse!
|
11
|
+
return puts option_parser.error_message if option_parser.error_message
|
12
|
+
if params[:name].nil?
|
13
|
+
print "name: "
|
14
|
+
params[:name] = $stdin.gets.chomp
|
15
|
+
end
|
16
|
+
|
17
|
+
user = Models::User.new(params)
|
18
|
+
result = user.create
|
19
|
+
return puts Utils::Color.reden "Failed create user" unless result
|
20
|
+
puts Utils::Color.greenen "Successed create user!"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "list", "List users"
|
24
|
+
def list(*options)
|
25
|
+
option_parser = Utils::OptionParserWrapper.new([])
|
26
|
+
option_parser.parse!
|
27
|
+
return puts option_parser.error_message if option_parser.error_message
|
28
|
+
|
29
|
+
users = Models::User.all
|
30
|
+
if users.empty?
|
31
|
+
puts Utils::Color.bluen "No users. Please create user first"
|
32
|
+
puts "ex) $ termworld user create --name=<name>"
|
33
|
+
return
|
34
|
+
end
|
35
|
+
users.each do |user|
|
36
|
+
puts "id:#{user.id} #{user.name}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "termworld/terminal/controller"
|
2
|
+
|
3
|
+
module Termworld
|
4
|
+
module Commands
|
5
|
+
class UserAction
|
6
|
+
def initialize(name)
|
7
|
+
@name = name
|
8
|
+
end
|
9
|
+
|
10
|
+
def wakeup(options)
|
11
|
+
res = $api_client.call_auth(:get, "/users/#{@name}")
|
12
|
+
puts Utils::Color.reden "Login required" if res.code == 401
|
13
|
+
puts Utils::Color.reden "User:#{@name} doesn't exsit" if res.code == 404
|
14
|
+
user = Models::User.new(JSON.parse(res.body, {symbolize_names: true})[:user])
|
15
|
+
user.initialize_position
|
16
|
+
user.save_local
|
17
|
+
if user.updated
|
18
|
+
puts Utils::Color.reden "User:#{user.name} already awake"
|
19
|
+
elsif user.created
|
20
|
+
puts Utils::Color.greenen "User:#{user.name} woke up!"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def sleep(options)
|
25
|
+
user = Models::User.new(name: @name)
|
26
|
+
user.delete_local(by: :name)
|
27
|
+
puts Utils::Color.greenen "User:#{user.name} slept!"
|
28
|
+
end
|
29
|
+
|
30
|
+
def terminal(options)
|
31
|
+
user = Models::User.new(name: @name)
|
32
|
+
if !user.bind_local_by_name
|
33
|
+
return puts Utils::Color.reden "User:#{@name} is not awake or doesn't exists"
|
34
|
+
end
|
35
|
+
terminal = Terminal::Controller.new(user)
|
36
|
+
terminal.run
|
37
|
+
end
|
38
|
+
|
39
|
+
def move(options)
|
40
|
+
if options.size != 1 || !%w(up down left right).include?(options.first)
|
41
|
+
puts Utils::Color.reden 'Direction must be only up, down, left or right'
|
42
|
+
puts "ex) $ termworld user:#{@name} move up"
|
43
|
+
return
|
44
|
+
end
|
45
|
+
direction = options.first.to_sym
|
46
|
+
user = Models::User.new(name: @name)
|
47
|
+
if !user.bind_local_by_name
|
48
|
+
return puts Utils::Color.reden "User:#{@name} is not awake or doesn't exists"
|
49
|
+
end
|
50
|
+
user.move(direction)
|
51
|
+
end
|
52
|
+
|
53
|
+
def method_missing(method, _)
|
54
|
+
puts Utils::Color.reden "#{method} command not found"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Termworld
|
2
|
+
class Credential
|
3
|
+
attr_reader :error_message
|
4
|
+
def logged_in?
|
5
|
+
if !File.exists?(Termworld::CREDENTIAL_FILE_NAME)
|
6
|
+
@error_message = Utils::Color.reden "Login required"
|
7
|
+
return false
|
8
|
+
end
|
9
|
+
email, token = Credential.get_credential
|
10
|
+
File.open(Termworld::CREDENTIAL_FILE_NAME) do |file|
|
11
|
+
email, token = file.read.split("\n")
|
12
|
+
end
|
13
|
+
res = $api_client.call(:post, '/login', {email: email, token: token})
|
14
|
+
if res.code != 200
|
15
|
+
@error_message = Utils::Color.reden "Wrong credential\nPlease login again"
|
16
|
+
return false
|
17
|
+
end
|
18
|
+
true
|
19
|
+
end
|
20
|
+
class << self
|
21
|
+
def get_credential
|
22
|
+
email, token = nil
|
23
|
+
begin
|
24
|
+
File.open(Termworld::CREDENTIAL_FILE_NAME) do |file|
|
25
|
+
email, token = file.read.split("\n")
|
26
|
+
end
|
27
|
+
rescue
|
28
|
+
return [nil, nil]
|
29
|
+
end
|
30
|
+
[email, token]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Termworld
|
2
|
+
class Daemon
|
3
|
+
attr_reader :error_message
|
4
|
+
def initialize(status = nil)
|
5
|
+
case status
|
6
|
+
when :start
|
7
|
+
@error_message = Utils::Color.reden "Already running" if alive?
|
8
|
+
when :stop
|
9
|
+
@error_message = Utils::Color.reden "Not running" unless alive?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def prepare
|
14
|
+
delete_files
|
15
|
+
[:INT, :TERM].each do |key|
|
16
|
+
Signal.trap(key) {@killed = true}
|
17
|
+
end
|
18
|
+
DB.setup
|
19
|
+
Process.setproctitle(Termworld::PROCESS_NAME)
|
20
|
+
File.write(Termworld::DAEMON_FILE_NAME, nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
Process.daemon(true, false) # (nochdir, noclose)
|
25
|
+
end
|
26
|
+
|
27
|
+
def alive?
|
28
|
+
@killed.nil? && daemon_file_exists && daemon_process_exists
|
29
|
+
end
|
30
|
+
|
31
|
+
def stop
|
32
|
+
delete_files
|
33
|
+
kill_daemon_process
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete_files
|
37
|
+
File.delete(Termworld::DAEMON_FILE_NAME) if File.exists?(Termworld::DAEMON_FILE_NAME)
|
38
|
+
File.delete(Termworld::DATABASE_NAME) if File.exists?(Termworld::DATABASE_NAME)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def kill_daemon_process
|
44
|
+
`ps aux | grep #{Termworld::PROCESS_NAME} | grep -v grep | awk '{print $2}' | xargs kill`
|
45
|
+
end
|
46
|
+
|
47
|
+
def daemon_file_exists
|
48
|
+
File.exists?(Termworld::DAEMON_FILE_NAME)
|
49
|
+
end
|
50
|
+
|
51
|
+
def daemon_process_exists
|
52
|
+
`ps aux | grep #{Termworld::PROCESS_NAME} | grep -v grep | wc -l`.delete(' ').to_i > 0
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/termworld/db.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
module Termworld
|
2
|
+
module Models
|
3
|
+
class User
|
4
|
+
attr_reader :id, :name, :created, :updated, :positionx, :positiony
|
5
|
+
class << self
|
6
|
+
def create_table
|
7
|
+
$db.create_table :users do
|
8
|
+
primary_key :id
|
9
|
+
String :name
|
10
|
+
String :current_map_name
|
11
|
+
Integer :positionx
|
12
|
+
Integer :positiony
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def all
|
17
|
+
res = $api_client.call_auth(:get, '/users')
|
18
|
+
return [] if res.code != 200
|
19
|
+
JSON.parse(res.body, {symbolize_names: true})[:users].map do |user|
|
20
|
+
self.new(user)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def all_local
|
25
|
+
$db[:users].all.map do |user|
|
26
|
+
self.new(user)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(params)
|
32
|
+
params.each { |key, value| instance_variable_set("@#{key}", value) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def bind_local_by_name
|
36
|
+
record = $db[:users].where(name: @name).first
|
37
|
+
return false if record.nil?
|
38
|
+
record.reject { |key, _| key == :name }.each { |key, value|
|
39
|
+
instance_variable_set("@#{key}", value)
|
40
|
+
}
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def create
|
45
|
+
validate
|
46
|
+
return false unless @errors.empty?
|
47
|
+
res = $api_client.call_auth(:post, '/users', {name: @name})
|
48
|
+
return false if res.code != 201
|
49
|
+
true
|
50
|
+
end
|
51
|
+
def save_local
|
52
|
+
validate
|
53
|
+
return false unless @errors.empty?
|
54
|
+
if record = $db[:users].where(id: @id).first
|
55
|
+
@created, @updated = false, true
|
56
|
+
$db[:users].where(id: @id).update(attributes_without_id)
|
57
|
+
else
|
58
|
+
@created, @updated = true, false
|
59
|
+
$db[:users].insert(attributes)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
def delete_local(by: nil)
|
63
|
+
if by == :id
|
64
|
+
$db[:users].where(id: @id).delete
|
65
|
+
elsif by == :name
|
66
|
+
$db[:users].where(name: @name).delete
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def validate
|
71
|
+
@errors = []
|
72
|
+
if @name.nil? || @name.empty?
|
73
|
+
@errors << "Name is required"
|
74
|
+
elsif !@name.scan(/[^0-9a-z]+/i).empty?
|
75
|
+
@errors << "Name must be only alphanumeric"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def attributes
|
80
|
+
{
|
81
|
+
id: @id,
|
82
|
+
name: @name,
|
83
|
+
current_map_name: @current_map_name,
|
84
|
+
positionx: @positionx,
|
85
|
+
positiony: @positiony,
|
86
|
+
}
|
87
|
+
end
|
88
|
+
def attributes_without_id
|
89
|
+
attributes.reject { |k, _| k == :id }
|
90
|
+
end
|
91
|
+
|
92
|
+
def initialize_position
|
93
|
+
@current_map_name = 'town'
|
94
|
+
@positionx = 0
|
95
|
+
@positiony = 0
|
96
|
+
end
|
97
|
+
|
98
|
+
def move(direction)
|
99
|
+
supposed_position = {x: @positionx, y: @positiony}
|
100
|
+
case direction
|
101
|
+
when :up
|
102
|
+
supposed_position[:y] -= 1
|
103
|
+
when :down
|
104
|
+
supposed_position[:y] += 1
|
105
|
+
when :left
|
106
|
+
supposed_position[:x] -= 1
|
107
|
+
when :right
|
108
|
+
supposed_position[:x] += 1
|
109
|
+
else
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
return false if supposed_position.any? { |_, v| v < 0 }
|
113
|
+
chip = current_map.get_chip(supposed_position)
|
114
|
+
return false if chip.nil? || !chip.movable
|
115
|
+
@positionx = supposed_position[:x]
|
116
|
+
@positiony = supposed_position[:y]
|
117
|
+
save_local
|
118
|
+
true
|
119
|
+
end
|
120
|
+
|
121
|
+
def current_map
|
122
|
+
@current_map ||= Object.const_get("Termworld::Resources::Maps::#{@current_map_name.capitalize}").new
|
123
|
+
@current_map
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "term_canvas"
|
2
|
+
|
3
|
+
module Termworld
|
4
|
+
module Resources
|
5
|
+
class Chip
|
6
|
+
attr_reader :movable
|
7
|
+
def initialize(y: nil, x: nil, key:)
|
8
|
+
@y = y
|
9
|
+
@x = x
|
10
|
+
@key = key
|
11
|
+
data
|
12
|
+
end
|
13
|
+
|
14
|
+
def data
|
15
|
+
case @key
|
16
|
+
when "00"
|
17
|
+
@movable = true
|
18
|
+
{
|
19
|
+
background_color: {r: 300, g: 300, b: 300},
|
20
|
+
}
|
21
|
+
when "01"
|
22
|
+
@movable = false
|
23
|
+
{
|
24
|
+
background_color: {r: 0, g: 0, b: 0},
|
25
|
+
}
|
26
|
+
when "pl"
|
27
|
+
{
|
28
|
+
background_color: {r: 200, b: 200, g: 800},
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def rect
|
34
|
+
TermCanvas::Rect.new(
|
35
|
+
x: @x, y: @y, width: 2, height: 1,
|
36
|
+
background_color: data[:background_color],
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Termworld
|
2
|
+
module Resources
|
3
|
+
module Maps
|
4
|
+
class Town
|
5
|
+
def chip_numbers
|
6
|
+
return @chip_numbers_lines if @chip_numbers_lines
|
7
|
+
chip_numbers_lines = <<'EOS'
|
8
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
9
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
10
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
11
|
+
00 00 00 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
12
|
+
00 00 00 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
13
|
+
00 00 00 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
14
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
15
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
16
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
17
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
18
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
19
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
20
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
21
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
22
|
+
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
23
|
+
EOS
|
24
|
+
@chip_numbers_lines = chip_numbers_lines.lines(chomp: true)
|
25
|
+
.map { |chip_numbers_line| chip_numbers_line.split }
|
26
|
+
@chip_numbers_lines
|
27
|
+
end
|
28
|
+
def get_chip(y:, x:)
|
29
|
+
chip_number = chip_numbers[y] && chip_numbers[y][x]
|
30
|
+
return nil if chip_number.nil?
|
31
|
+
chip = Resources::Chip.new(y: y, x: x, key: chip_number)
|
32
|
+
chip
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "term_canvas"
|
2
|
+
|
3
|
+
require "termworld/resources/chip"
|
4
|
+
require "termworld/resources/maps/town"
|
5
|
+
|
6
|
+
module Termworld
|
7
|
+
module Terminal
|
8
|
+
class Controller
|
9
|
+
def initialize(user)
|
10
|
+
@user = user
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
field = TermCanvas::Canvas.new(x: 0, y: 0, w: TermCanvas.width, h: TermCanvas.height)
|
15
|
+
|
16
|
+
map = Resources::Maps::Town.new
|
17
|
+
loop do
|
18
|
+
@user.bind_local_by_name
|
19
|
+
users = Models::User.all_local.reject { |user| user.name == @user.name }
|
20
|
+
|
21
|
+
break if handle_keys == :break
|
22
|
+
field.clear
|
23
|
+
|
24
|
+
height = field.height
|
25
|
+
width = field.width / 2 - 1
|
26
|
+
height.times do |y|
|
27
|
+
width.times do |x|
|
28
|
+
abs_position = {
|
29
|
+
x: @user.positionx - (width / 2) + x,
|
30
|
+
y: @user.positiony - (height / 2) + y,
|
31
|
+
}
|
32
|
+
user = users.find { |u|
|
33
|
+
u.positionx == abs_position[:x] && u.positiony == abs_position[:y]
|
34
|
+
}
|
35
|
+
if user
|
36
|
+
player_chip = Resources::Chip.new(x: x * 2 + 1, y: y, key: "pl")
|
37
|
+
field.rect(player_chip.rect)
|
38
|
+
next
|
39
|
+
end
|
40
|
+
next if abs_position.any? { |_, v| v < 0 }
|
41
|
+
next if (chip = map.get_chip(abs_position)).nil?
|
42
|
+
field.rect(chip.rect.position_override(x: x * 2 + 1, y: y))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
player_chip = Resources::Chip.new(x: field.centerx, y: field.centery, key: "pl")
|
47
|
+
field.rect(player_chip.rect)
|
48
|
+
|
49
|
+
field.update
|
50
|
+
sleep 0.05
|
51
|
+
end
|
52
|
+
TermCanvas.close
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def handle_keys
|
58
|
+
key = TermCanvas.gets
|
59
|
+
case key
|
60
|
+
when ?q
|
61
|
+
return :break
|
62
|
+
when ?h
|
63
|
+
@user.move(:left)
|
64
|
+
when ?j
|
65
|
+
@user.move(:down)
|
66
|
+
when ?k
|
67
|
+
@user.move(:up)
|
68
|
+
when ?l
|
69
|
+
@user.move(:right)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "httpclient"
|
2
|
+
|
3
|
+
module Termworld
|
4
|
+
module Utils
|
5
|
+
class ApiClient
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@client = HTTPClient.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(method, url, params = nil)
|
12
|
+
if method == :get
|
13
|
+
res = @client.get(Termworld::API_ENDPOINT + url, query: params)
|
14
|
+
else
|
15
|
+
res = @client.send(method, Termworld::API_ENDPOINT + url, body: params)
|
16
|
+
end
|
17
|
+
res
|
18
|
+
end
|
19
|
+
|
20
|
+
def call_auth(method, url, params = nil)
|
21
|
+
email, token = Credential.get_credential
|
22
|
+
headers = {
|
23
|
+
'X-Termworld-Email': email,
|
24
|
+
'X-Termworld-Token': token,
|
25
|
+
}
|
26
|
+
if method == :get
|
27
|
+
res = @client.get(Termworld::API_ENDPOINT + url, query: params, header: headers)
|
28
|
+
else
|
29
|
+
res = @client.send(method, Termworld::API_ENDPOINT + url, body: params, header: headers)
|
30
|
+
end
|
31
|
+
res
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Termworld
|
2
|
+
module Utils
|
3
|
+
class Color
|
4
|
+
class << self
|
5
|
+
def reden(str)
|
6
|
+
"\e[31m#{str}\e[0m"
|
7
|
+
end
|
8
|
+
def greenen(str)
|
9
|
+
"\e[32m#{str}\e[0m"
|
10
|
+
end
|
11
|
+
def yellowen(str)
|
12
|
+
"\e[33m#{str}\e[0m"
|
13
|
+
end
|
14
|
+
def bluen(str)
|
15
|
+
"\e[34m#{str}\e[0m"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module Termworld
|
4
|
+
module Utils
|
5
|
+
class OptionParserWrapper
|
6
|
+
attr_reader :error_message
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
def parse!
|
11
|
+
params = {}
|
12
|
+
begin
|
13
|
+
OptionParser.new do |op|
|
14
|
+
@options.each do |option|
|
15
|
+
op.on(*option[:option]) { |v| params[option[:key]] = v }
|
16
|
+
end
|
17
|
+
op.parse!(params)
|
18
|
+
end
|
19
|
+
rescue OptionParser::InvalidOption => e
|
20
|
+
@error_message = Utils::Color.reden "Invalid options: #{e.args.first}"
|
21
|
+
return {}
|
22
|
+
end
|
23
|
+
params
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/termworld.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
lib = File.expand_path("../lib", __FILE__)
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require "termworld"
|
3
|
+
require "termworld/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "termworld"
|
@@ -23,6 +23,8 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency "thor"
|
24
24
|
spec.add_dependency "sequel"
|
25
25
|
spec.add_dependency "sqlite3"
|
26
|
+
spec.add_dependency "httpclient"
|
27
|
+
spec.add_dependency "term_canvas", "0.2.9"
|
26
28
|
|
27
29
|
spec.add_development_dependency "bundler", "~> 2.0"
|
28
30
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: termworld
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kthatoto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: httpclient
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: term_canvas
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.2.9
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.2.9
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: bundler
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -132,9 +160,22 @@ files:
|
|
132
160
|
- exe/termworld
|
133
161
|
- lib/termworld.rb
|
134
162
|
- lib/termworld/cli.rb
|
135
|
-
- lib/termworld/
|
136
|
-
- lib/termworld/
|
137
|
-
- lib/termworld/
|
163
|
+
- lib/termworld/commands/account.rb
|
164
|
+
- lib/termworld/commands/daemon_operator.rb
|
165
|
+
- lib/termworld/commands/user.rb
|
166
|
+
- lib/termworld/commands/user_action.rb
|
167
|
+
- lib/termworld/config.rb
|
168
|
+
- lib/termworld/credential.rb
|
169
|
+
- lib/termworld/daemon.rb
|
170
|
+
- lib/termworld/db.rb
|
171
|
+
- lib/termworld/models/user.rb
|
172
|
+
- lib/termworld/resources/chip.rb
|
173
|
+
- lib/termworld/resources/maps/town.rb
|
174
|
+
- lib/termworld/terminal/controller.rb
|
175
|
+
- lib/termworld/utils/api_client.rb
|
176
|
+
- lib/termworld/utils/color.rb
|
177
|
+
- lib/termworld/utils/option_parser_wrapper.rb
|
178
|
+
- lib/termworld/version.rb
|
138
179
|
- termworld.gemspec
|
139
180
|
homepage: https://github.com/kthatoto/termworld
|
140
181
|
licenses:
|
data/lib/termworld/db/db.rb
DELETED