ledmon 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CLAUDE.md +73 -0
- data/DOCS.md +333 -0
- data/lib/ledmon/cli/monster.rb +107 -0
- data/lib/ledmon/monster/interaction.rb +9 -1
- data/lib/ledmon/monster/movement.rb +46 -4
- data/lib/ledmon/monster/session.rb +2 -0
- data/lib/ledmon/version.rb +1 -1
- data/lib/ledmon/world_pb.rb +3 -1
- data/lib/ledmon/world_services_pb.rb +1 -0
- data/lib/ledmon.rb +4 -0
- data/protos/world.proto +14 -2
- metadata +45 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa51679f40d2362bf2da0a15423c8e4c1d429fbbd251712b34da77860763cbe2
|
4
|
+
data.tar.gz: c3bb466c875167945f57679a5d5240817a2c242bf5decb6359a7cda7a9a678c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82484fce2c6034c1a94fb01266145beac95e5e71ddda57857b1f60b539fb80c68390b5b492d74ed075525914dbe352e4c7fda4663b99bebe0c507dd04a599a56
|
7
|
+
data.tar.gz: de76543c3ec225ec19bbc1e67fed1ffb819c040909ac82dc90d0694185e930ecc8980b34968471ca62cf6ba615567e45f7446713fd1ce78ddeb3fd6ca7300912
|
data/CLAUDE.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# CLAUDE.md
|
2
|
+
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
4
|
+
|
5
|
+
## Development Commands
|
6
|
+
|
7
|
+
- **Bundle install**: `bundle install` - Install Ruby gem dependencies
|
8
|
+
- **Run locally**: `bundle exec exe/ledmon monster local` - Run the monster client locally (requires monster.rb file)
|
9
|
+
- **Deploy monster**: `bundle exec exe/ledmon monster deploy` - Deploy monster code to remote server
|
10
|
+
- **View logs**: `bundle exec exe/ledmon monster logs` - Fetch logs from deployed monster
|
11
|
+
- **Run tests**: `bundle exec rake spec` - Run RSpec test suite
|
12
|
+
- **Build gem**: `bundle exec rake build` - Build the gem package
|
13
|
+
- **Update protobuf**: `make update_protos` - Sync protobuf files from engine project
|
14
|
+
- **Generate protobuf**: `make generate` - Generate Ruby protobuf/gRPC files from .proto
|
15
|
+
|
16
|
+
## Architecture Overview
|
17
|
+
|
18
|
+
Ledmon is a Ruby gem for managing and deploying monsters in a game environment. The architecture consists of:
|
19
|
+
|
20
|
+
### Core Components
|
21
|
+
|
22
|
+
- **CLI System**: Thor-based command line interface in `lib/ledmon/cli/`
|
23
|
+
- `Main` - Entry point with version, config, and monster subcommands
|
24
|
+
- `Monster` - Handles local running, deployment, and log fetching
|
25
|
+
- `Config` - Configuration management
|
26
|
+
|
27
|
+
- **Monster System**: Core game logic in `lib/ledmon/monster/`
|
28
|
+
- `Runner` - Orchestrates local monster execution, loads monster.rb scripts
|
29
|
+
- `Session` - Manages gRPC connection to game server with keep-alive
|
30
|
+
- `Executor` - Provides DSL and execution context for monster scripts
|
31
|
+
- `Deployer` - Handles remote deployment via HTTP API
|
32
|
+
- `Packer` - Creates deployment bundles
|
33
|
+
- `Terminal` - Terminal interaction utilities
|
34
|
+
- `Movement` - Movement-related functionality
|
35
|
+
- `Interaction` - Game interaction handling
|
36
|
+
|
37
|
+
### Configuration System
|
38
|
+
|
39
|
+
- Uses TTY::Config with `.ledmon` files and `LEDMON_*` environment variables
|
40
|
+
- Key settings: host, grpc_port, http_port, auth token, mode, log_level
|
41
|
+
- Default server: `ledmon.lstme.sk:50051` (gRPC), port 443 (HTTPS)
|
42
|
+
|
43
|
+
### gRPC Communication
|
44
|
+
|
45
|
+
- Protobuf definitions in `protos/world.proto` define the game API
|
46
|
+
- Generated Ruby files: `world_pb.rb` and `world_services_pb.rb`
|
47
|
+
- Sleep interceptor handles server-imposed delays
|
48
|
+
- Bi-directional streaming for sessions and interactions
|
49
|
+
|
50
|
+
### Monster Scripts
|
51
|
+
|
52
|
+
- User-provided `monster.rb` files define bot behavior
|
53
|
+
- Must implement `avatar` (ASCII art) and `brain` (main loop) methods
|
54
|
+
- Optional `algo` method for challenge responses
|
55
|
+
- DSL provides methods for movement, crafting, inventory, combat, etc.
|
56
|
+
|
57
|
+
## Key Dependencies
|
58
|
+
|
59
|
+
- **zeitwerk**: Code loading and autoloading
|
60
|
+
- **grpc**: Protocol buffer communication with game server
|
61
|
+
- **thor**: CLI framework
|
62
|
+
- **tty-config**: Configuration management
|
63
|
+
- **activesupport**: Ruby extensions and utilities
|
64
|
+
- **http**: HTTP client for deployment API
|
65
|
+
|
66
|
+
## Project Structure
|
67
|
+
|
68
|
+
- `exe/ledmon` - Main executable entry point
|
69
|
+
- `lib/ledmon.rb` - Gem initialization and autoloader setup
|
70
|
+
- `lib/ledmon/` - Core implementation modules
|
71
|
+
- `protos/` - Protocol buffer definitions (synced from engine project)
|
72
|
+
- `monster.rb.sample` - Example monster script with keyboard controls
|
73
|
+
- `spec/` - RSpec test files
|
data/DOCS.md
ADDED
@@ -0,0 +1,333 @@
|
|
1
|
+
# Ledmon API - Dokumentácia
|
2
|
+
|
3
|
+
Táto dokumentácia ti ukáže, ako naprogramovať svoju vlastnú príšerku v hre! 🎮
|
4
|
+
|
5
|
+
## Základná štruktúra
|
6
|
+
|
7
|
+
Každé monster.rb musí obsahovať:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
def avatar
|
11
|
+
# ASCII obrázok tvojej príšerky
|
12
|
+
"@@@@@
|
13
|
+
@)))@
|
14
|
+
@)?)@
|
15
|
+
@)?)@
|
16
|
+
@)<)@"
|
17
|
+
end
|
18
|
+
|
19
|
+
def brain
|
20
|
+
# Mozog príšerky - tu sa všetko odohráva!
|
21
|
+
loop do
|
22
|
+
# Tvoja logika
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def algo(id, input)
|
27
|
+
# Riešenie algoritmických úloh
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
## 🎮 Ovládanie a vstup
|
32
|
+
|
33
|
+
### `keypress`
|
34
|
+
Počká na stlačenie klávesy a vráti aká bola stlačená.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
key = keypress
|
38
|
+
if key == 'w'
|
39
|
+
move_forward
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
### `ask(otazka)`
|
44
|
+
Opýta sa užívateľa na niečo a počká na odpoveď.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
recipe = ask("Zadaj meno receptu: ")
|
48
|
+
craft(recipe)
|
49
|
+
```
|
50
|
+
|
51
|
+
### `say(sprava)`
|
52
|
+
Vypíše správu na obrazovku.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
say "Ahoj svet!"
|
56
|
+
say "Môj život: #{get_health}"
|
57
|
+
```
|
58
|
+
|
59
|
+
## 🚶 Pohyb
|
60
|
+
|
61
|
+
### `move_forward`
|
62
|
+
Pohne príšerku vpred (v smere, kam sa pozerá).
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
if key == 'w'
|
66
|
+
move_forward
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
### `move_backward`
|
71
|
+
Pohne príšerku vzad.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
if key == 's'
|
75
|
+
move_backward
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
### `turn_left`
|
80
|
+
Otočí príšerku doľava.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
if key == 'a'
|
84
|
+
turn_left
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
### `turn_right`
|
89
|
+
Otočí príšerku doprava.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
if key == 'd'
|
93
|
+
turn_right
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
### `turn_towards(smer)`
|
98
|
+
Otočí príšerku vybraným smerom.
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
turn_towards(["north", "south", "east", "west"].sample)
|
102
|
+
```
|
103
|
+
|
104
|
+
### `get_position`
|
105
|
+
Vráti ti aktuálnu pozíciu príšerky.
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
if key == 'n'
|
109
|
+
say "#{get_position.x, get_position.y}"
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
### `get_heading`
|
114
|
+
Vráti ti aktuálny smer príšerky.
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
if key == 'm'
|
118
|
+
say "#{get_heading}"
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
## 👀 Rozhliadanie sa
|
123
|
+
|
124
|
+
### `look`
|
125
|
+
Pozrie sa okolo seba a vráti mapu okolia.
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
tiles = look
|
129
|
+
|
130
|
+
for col in tiles
|
131
|
+
for tile in col
|
132
|
+
if tile.entities.size > 0
|
133
|
+
print "E" # Entita (príšerka/hráč)
|
134
|
+
elsif tile.walkable
|
135
|
+
print " " # Voľné miesto
|
136
|
+
else
|
137
|
+
print "O" # Prekážka
|
138
|
+
end
|
139
|
+
end
|
140
|
+
puts ""
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
## ⚔️ Boj
|
145
|
+
|
146
|
+
### `attack`
|
147
|
+
Zaútočí na nepriateľa, ak pred ním stojí.
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
if key == 'j'
|
151
|
+
attack
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
### `get_health`
|
156
|
+
Zistí aktuálny život príšerky.
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
health = get_health
|
160
|
+
say "Môj život: #{health}"
|
161
|
+
```
|
162
|
+
|
163
|
+
## 🎒 Inventár a vybavenie
|
164
|
+
|
165
|
+
### `get_inventory`
|
166
|
+
Vráti všetky predmety v inventári.
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
inventory = get_inventory
|
170
|
+
say "Predmety: #{inventory.items.inspect}"
|
171
|
+
say "Vybavenie: #{inventory.equipment.inspect}"
|
172
|
+
```
|
173
|
+
|
174
|
+
### `equip_item(predmet, slot)`
|
175
|
+
Nasadí predmet do určitého slotu.
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
item = ask("Predmet: ")
|
179
|
+
slot = ask("Slot: ")
|
180
|
+
equip_item(item, slot)
|
181
|
+
```
|
182
|
+
|
183
|
+
### `unequip_item(slot)`
|
184
|
+
Zosadí predmet zo slotu.
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
slot = ask("Slot: ")
|
188
|
+
unequip_item(slot)
|
189
|
+
```
|
190
|
+
|
191
|
+
## 🔨 Crafting a výskum
|
192
|
+
|
193
|
+
### `craft(recept)`
|
194
|
+
Vytvorí predmet podľa receptu.
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
recipe = ask("Meno receptu: ")
|
198
|
+
craft(recipe)
|
199
|
+
```
|
200
|
+
|
201
|
+
### `research(predmet)`
|
202
|
+
Začne výskum určitého predmetu.
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
item = ask("Vyskumaj predmet: ")
|
206
|
+
research(item)
|
207
|
+
```
|
208
|
+
|
209
|
+
### `get_research_progress`
|
210
|
+
Zobrazí stav výskumu.
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
progress = get_research_progress
|
214
|
+
say "Stav výskumu: #{progress}"
|
215
|
+
```
|
216
|
+
|
217
|
+
### `get_recipes`
|
218
|
+
Zobrazí všetky dostupné recepty.
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
recipes = get_recipes
|
222
|
+
say "Recepty: #{recipes}"
|
223
|
+
```
|
224
|
+
|
225
|
+
### `scrap(predmet)`
|
226
|
+
Rozloží predmet na materiály.
|
227
|
+
|
228
|
+
```ruby
|
229
|
+
scrap("iron_sword")
|
230
|
+
```
|
231
|
+
|
232
|
+
## 🧩 Výzvy a algoritmy
|
233
|
+
|
234
|
+
### `interact`
|
235
|
+
Interaguje s objektami vo svete, môže spustiť algoritmickú úlohu.
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
success, challenge_id, input, output = interact
|
239
|
+
if success
|
240
|
+
say "Úlohu som vyriešil!"
|
241
|
+
else
|
242
|
+
say "Úlohu sa nepodarilo vyriešiť :-("
|
243
|
+
end
|
244
|
+
```
|
245
|
+
|
246
|
+
### `algo(id, input)`
|
247
|
+
Rieši algoritmické úlohy. Musíš implementovať logiku pre rôzne typy úloh.
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
def algo(id, input)
|
251
|
+
case id
|
252
|
+
when 'identifikator ulohy'
|
253
|
+
# Sčítaj všetky číslice v reťazci
|
254
|
+
input.chars.map(&:to_i).sum
|
255
|
+
else
|
256
|
+
nil
|
257
|
+
end
|
258
|
+
end
|
259
|
+
```
|
260
|
+
|
261
|
+
## 💡 Kompletný príklad
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
def avatar
|
265
|
+
"@@@@@
|
266
|
+
@)))@
|
267
|
+
@)?)@
|
268
|
+
@)?)@
|
269
|
+
@)<)@"
|
270
|
+
end
|
271
|
+
|
272
|
+
def brain
|
273
|
+
loop do
|
274
|
+
key = keypress
|
275
|
+
|
276
|
+
case key
|
277
|
+
when 'w' then move_forward
|
278
|
+
when 's' then move_backward
|
279
|
+
when 'a' then turn_left
|
280
|
+
when 'd' then turn_right
|
281
|
+
when 'j' then attack
|
282
|
+
when 'l' then
|
283
|
+
# Pozri sa okolo
|
284
|
+
tiles = look
|
285
|
+
for col in tiles
|
286
|
+
for tile in col
|
287
|
+
if tile.entities.size > 0
|
288
|
+
print "E"
|
289
|
+
elsif tile.walkable
|
290
|
+
print " "
|
291
|
+
else
|
292
|
+
print "O"
|
293
|
+
end
|
294
|
+
end
|
295
|
+
puts ""
|
296
|
+
end
|
297
|
+
when 'i' then
|
298
|
+
# Zobraz inventár
|
299
|
+
inventory = get_inventory
|
300
|
+
say "Predmety: #{inventory.items.inspect}"
|
301
|
+
say "Vybavenie: #{inventory.equipment.inspect}"
|
302
|
+
when 'u' then
|
303
|
+
# Zobraz život
|
304
|
+
say "Život: #{get_health}"
|
305
|
+
when 'n' then
|
306
|
+
say "#{get_position.x} #{get_position.y} #{get_heading}"
|
307
|
+
when 'c' then
|
308
|
+
# Craftovanie
|
309
|
+
recipe = ask("Meno receptu: ")
|
310
|
+
craft(recipe)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def algo(id, input)
|
316
|
+
case id
|
317
|
+
when 'abc'
|
318
|
+
input.chars.map(&:to_i).sum
|
319
|
+
else
|
320
|
+
nil
|
321
|
+
end
|
322
|
+
end
|
323
|
+
```
|
324
|
+
|
325
|
+
## 🎯 Tipy pre začiatočníkov
|
326
|
+
|
327
|
+
1. **Začni jednoducho** - najprv vytvor príšerku, ktorá sa len pohybuje
|
328
|
+
2. **Testuj postupne** - pridávaj funkcie jednu po druhej
|
329
|
+
3. **Používaj `say`** - vypisuj si informácie, aby si videl, co sa deje
|
330
|
+
4. **Experimentuj** - skúšaj rôzne kombinácie príkazov
|
331
|
+
5. **Pozri sa na sample** - monster.rb.sample obsahuje dobrý príklad
|
332
|
+
|
333
|
+
Veľa zábavy s programovaním svojej príšerky! 🚀
|
data/lib/ledmon/cli/monster.rb
CHANGED
@@ -60,5 +60,112 @@ module Ledmon::CLI
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
63
|
+
|
64
|
+
desc 'docs', 'Generate and open API documentation in browser'
|
65
|
+
|
66
|
+
def docs
|
67
|
+
say "Generating API documentation ...", :yellow
|
68
|
+
|
69
|
+
# Find DOCS.md file from gem root
|
70
|
+
docs_path = File.join(Ledmon.root, 'DOCS.md')
|
71
|
+
|
72
|
+
unless File.exist?(docs_path)
|
73
|
+
say_error "DOCS.md not found in current directory", :red
|
74
|
+
exit 1
|
75
|
+
end
|
76
|
+
|
77
|
+
# Read markdown content
|
78
|
+
markdown_content = File.read(docs_path)
|
79
|
+
|
80
|
+
# Convert to HTML
|
81
|
+
html_content = markdown_to_html(markdown_content)
|
82
|
+
|
83
|
+
# Create temporary HTML file
|
84
|
+
require 'tempfile'
|
85
|
+
Tempfile.create(%w[ledmon-docs .html]) do |temp_file|
|
86
|
+
temp_file.write(html_content)
|
87
|
+
temp_file.close
|
88
|
+
|
89
|
+
say "Opening documentation in browser ...", :green
|
90
|
+
|
91
|
+
# Open in default browser using launchy
|
92
|
+
require 'launchy'
|
93
|
+
Launchy.open("file://#{temp_file.path}")
|
94
|
+
|
95
|
+
say "Documentation opened! Press any key to continue ...", :cyan
|
96
|
+
STDIN.getch rescue nil
|
97
|
+
end
|
98
|
+
rescue Ledmon::Error => e
|
99
|
+
say_error e.message, :red
|
100
|
+
exit 1
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def markdown_to_html(markdown)
|
106
|
+
require 'redcarpet'
|
107
|
+
require 'rouge'
|
108
|
+
require 'rouge/plugins/redcarpet'
|
109
|
+
|
110
|
+
renderer = Class.new(Redcarpet::Render::HTML)
|
111
|
+
.tap do |klass|
|
112
|
+
klass.include Rouge::Plugins::Redcarpet
|
113
|
+
end
|
114
|
+
.new(
|
115
|
+
filter_html: false,
|
116
|
+
no_intra_emphasis: true,
|
117
|
+
fenced_code_blocks: true,
|
118
|
+
autolink: true,
|
119
|
+
strikethrough: true,
|
120
|
+
superscript: true
|
121
|
+
)
|
122
|
+
|
123
|
+
redcarpet = Redcarpet::Markdown.new(
|
124
|
+
renderer,
|
125
|
+
autolink: true,
|
126
|
+
fenced_code_blocks: true,
|
127
|
+
no_intra_emphasis: true,
|
128
|
+
strikethrough: true,
|
129
|
+
superscript: true,
|
130
|
+
tables: true
|
131
|
+
)
|
132
|
+
|
133
|
+
html_body = redcarpet.render(markdown)
|
134
|
+
rouge_css = Rouge::Themes::Github.render(scope: '.highlight')
|
135
|
+
|
136
|
+
# Wrap in HTML template
|
137
|
+
<<~HTML
|
138
|
+
<!DOCTYPE html>
|
139
|
+
<html>
|
140
|
+
<head>
|
141
|
+
<meta charset="utf-8">
|
142
|
+
<title>Ledmon API Documentation</title>
|
143
|
+
<style>
|
144
|
+
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; line-height: 1.6; }
|
145
|
+
h1, h2, h3 { color: #333; }
|
146
|
+
h1 { border-bottom: 2px solid #333; padding-bottom: 10px; }
|
147
|
+
h2 { border-bottom: 1px solid #ccc; margin-top: 30px; padding-bottom: 5px; }
|
148
|
+
h3 { margin-top: 25px; }
|
149
|
+
code { background: #f4f4f4; padding: 2px 4px; border-radius: 3px; font-family: 'Monaco', 'Courier New', monospace; }
|
150
|
+
pre { background: #f8f8f8; padding: 15px; border-radius: 5px; overflow-x: auto; border: 1px solid #e1e1e1; }
|
151
|
+
pre code { background: none; padding: 0; }
|
152
|
+
li { margin: 5px 0; }
|
153
|
+
ul, ol { margin: 10px 0; padding-left: 30px; }
|
154
|
+
blockquote { border-left: 4px solid #ddd; margin: 0; padding-left: 20px; color: #666; }
|
155
|
+
table { border-collapse: collapse; width: 100%; margin: 10px 0; }
|
156
|
+
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
157
|
+
th { background-color: #f2f2f2; }
|
158
|
+
.emoji { font-size: 1.2em; }
|
159
|
+
|
160
|
+
#{rouge_css}
|
161
|
+
</style>
|
162
|
+
</head>
|
163
|
+
<body>
|
164
|
+
#{html_body}
|
165
|
+
</body>
|
166
|
+
</html>
|
167
|
+
HTML
|
168
|
+
end
|
169
|
+
|
63
170
|
end
|
64
171
|
end
|
@@ -53,6 +53,14 @@ module Ledmon::Monster
|
|
53
53
|
client.research(Ledmon::ItemInfo.new(item:))
|
54
54
|
end
|
55
55
|
|
56
|
+
def get_research_progress
|
57
|
+
client.get_research_progress(Ledmon::Empty.new)
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_recipes
|
61
|
+
client.get_recipes(Ledmon::Empty.new)
|
62
|
+
end
|
63
|
+
|
56
64
|
def scrap(item)
|
57
65
|
client.scrap(Ledmon::ItemInfo.new(item:))
|
58
66
|
end
|
@@ -91,4 +99,4 @@ module Ledmon::Monster
|
|
91
99
|
tiles
|
92
100
|
end
|
93
101
|
end
|
94
|
-
end
|
102
|
+
end
|
@@ -3,19 +3,61 @@ module Ledmon::Monster
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
def move_forward
|
6
|
-
client.move_forward(Ledmon::Empty.new)
|
6
|
+
res = client.move_forward(Ledmon::Empty.new)
|
7
|
+
update_movement(res)
|
8
|
+
res
|
7
9
|
end
|
8
10
|
|
9
11
|
def move_backward
|
10
|
-
client.move_backward(Ledmon::Empty.new)
|
12
|
+
res = client.move_backward(Ledmon::Empty.new)
|
13
|
+
update_movement(res)
|
14
|
+
res
|
11
15
|
end
|
12
16
|
|
13
17
|
def turn_left
|
14
|
-
client.turn_left(Ledmon::Empty.new)
|
18
|
+
res = client.turn_left(Ledmon::Empty.new)
|
19
|
+
update_movement(res)
|
20
|
+
res
|
15
21
|
end
|
16
22
|
|
17
23
|
def turn_right
|
18
|
-
client.turn_right(Ledmon::Empty.new)
|
24
|
+
res = client.turn_right(Ledmon::Empty.new)
|
25
|
+
update_movement(res)
|
26
|
+
res
|
27
|
+
end
|
28
|
+
|
29
|
+
def turn_towards(new_heading)
|
30
|
+
return if new_heading == get_heading
|
31
|
+
|
32
|
+
left = case get_heading
|
33
|
+
when "north"
|
34
|
+
"west"
|
35
|
+
when "east"
|
36
|
+
"north"
|
37
|
+
when "south"
|
38
|
+
"east"
|
39
|
+
when "west"
|
40
|
+
"south"
|
41
|
+
end
|
42
|
+
|
43
|
+
if new_heading==left
|
44
|
+
turn_left
|
45
|
+
else
|
46
|
+
turn_right
|
47
|
+
turn_towards(new_heading)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_movement(movement)
|
52
|
+
@position = movement.position
|
53
|
+
@heading = movement.heading
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_position
|
57
|
+
@position
|
58
|
+
end
|
59
|
+
def get_heading
|
60
|
+
@heading
|
19
61
|
end
|
20
62
|
end
|
21
63
|
end
|
data/lib/ledmon/version.rb
CHANGED
data/lib/ledmon/world_pb.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
require 'google/protobuf'
|
6
6
|
|
7
7
|
|
8
|
-
descriptor_data = "\n\x0bworld.proto\x12\x06ledmon\"\x07\n\x05\x45mpty\"\x84\x01\n\x07MapInfo\x12\r\n\x05width\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x05\x12\x10\n\x08tilesize\x18\x03 \x01(\x05\x12\x0f\n\x07spawn_x\x18\x04 \x01(\x05\x12\x0f\n\x07spawn_y\x18\x05 \x01(\x05\x12\x13\n\x0b\x66og_enabled\x18\x06 \x01(\x08\x12\x11\n\tmap_image\x18\x07 \x01(\t\"\'\n\tEquipInfo\x12\x0c\n\x04item\x18\x01 \x01(\t\x12\x0c\n\x04slot\x18\x02 \x01(\t\"\x1b\n\x0bUnequipInfo\x12\x0c\n\x04slot\x18\x01 \x01(\t\"\x1c\n\tPingReply\x12\x0f\n\x07message\x18\x01 \x01(\t\"0\n\x0eSessionRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12\x0f\n\x07\x61vatars\x18\x02 \x03(\t\"\x1d\n\x0b\x41vatarIndex\x12\x0e\n\x06\x61vatar\x18\x01 \x01(\x05\"
|
8
|
+
descriptor_data = "\n\x0bworld.proto\x12\x06ledmon\"\x07\n\x05\x45mpty\"\x84\x01\n\x07MapInfo\x12\r\n\x05width\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x05\x12\x10\n\x08tilesize\x18\x03 \x01(\x05\x12\x0f\n\x07spawn_x\x18\x04 \x01(\x05\x12\x0f\n\x07spawn_y\x18\x05 \x01(\x05\x12\x13\n\x0b\x66og_enabled\x18\x06 \x01(\x08\x12\x11\n\tmap_image\x18\x07 \x01(\t\"\'\n\tEquipInfo\x12\x0c\n\x04item\x18\x01 \x01(\t\x12\x0c\n\x04slot\x18\x02 \x01(\t\"\x1b\n\x0bUnequipInfo\x12\x0c\n\x04slot\x18\x01 \x01(\t\"\x1c\n\tPingReply\x12\x0f\n\x07message\x18\x01 \x01(\t\"0\n\x0eSessionRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12\x0f\n\x07\x61vatars\x18\x02 \x03(\t\"\x1d\n\x0b\x41vatarIndex\x12\x0e\n\x06\x61vatar\x18\x01 \x01(\x05\"\x81\x01\n\x0cSessionReply\x12%\n\x06status\x18\x01 \x01(\x0e\x32\x15.ledmon.SessionStatus\x12\x0c\n\x04name\x18\x02 \x01(\t\x12/\n\x08movement\x18\x03 \x01(\x0b\x32\x18.ledmon.MovementResponseH\x00\x88\x01\x01\x42\x0b\n\t_movement\"F\n\nStateReply\x12\x12\n\x05state\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04\x64iff\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_stateB\x07\n\x05_diff\" \n\x08Position\x12\t\n\x01x\x18\x01 \x01(\x05\x12\t\n\x01y\x18\x02 \x01(\x05\"\xa6\x01\n\x10MovementResponse\x12&\n\x06result\x18\x01 \x01(\x0e\x32\x16.ledmon.MovementResult\x12\'\n\x08position\x18\x02 \x01(\x0b\x32\x10.ledmon.PositionH\x00\x88\x01\x01\x12\x12\n\nsleep_time\x18\x03 \x01(\x02\x12\x14\n\x07heading\x18\x04 \x01(\tH\x01\x88\x01\x01\x42\x0b\n\t_positionB\n\n\x08_heading\"~\n\x12InteractionRequest\x12\x30\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32 .ledmon.InteractionRequestAction\x12\x1f\n\x12\x63hallenge_response\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x15\n\x13_challenge_response\"\xa6\x01\n\x13InteractionResponse\x12\x31\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32!.ledmon.InteractionResponseAction\x12\x19\n\x0c\x63hallenge_id\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x1c\n\x0f\x63hallenge_input\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x0f\n\r_challenge_idB\x12\n\x10_challenge_input\"\x89\x01\n\rInventoryData\x12\r\n\x05items\x18\x01 \x03(\t\x12\x37\n\tequipment\x18\x02 \x03(\x0b\x32$.ledmon.InventoryData.EquipmentEntry\x1a\x30\n\x0e\x45quipmentEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x1b\n\tCraftData\x12\x0e\n\x06recipe\x18\x01 \x01(\t\"\x18\n\x08ItemInfo\x12\x0c\n\x04item\x18\x01 \x01(\t\"\x1d\n\x0bHealthCount\x12\x0e\n\x06health\x18\x01 \x01(\x02\"J\n\x0e\x41\x63tionResponse\x12$\n\x06result\x18\x01 \x01(\x0e\x32\x14.ledmon.ActionResult\x12\x12\n\nsleep_time\x18\x02 \x01(\x02\"U\n\x0cLookResponse\x12\x1f\n\x05tiles\x18\x01 \x03(\x0b\x32\x10.ledmon.LookTile\x12\x10\n\x08\x64istance\x18\x02 \x01(\x05\x12\x12\n\nsleep_time\x18\x03 \x01(\x02\"\x80\x01\n\x08LookTile\x12\x10\n\x08walkable\x18\x01 \x01(\x08\x12\x14\n\x07station\x18\x02 \x01(\tH\x00\x88\x01\x01\x12$\n\x08\x65ntities\x18\x03 \x03(\x0b\x32\x12.ledmon.LookEntity\x12\x11\n\x04zone\x18\x04 \x01(\tH\x01\x88\x01\x01\x42\n\n\x08_stationB\x07\n\x05_zone\"O\n\nLookEntity\x12\n\n\x02id\x18\x01 \x01(\t\x12\"\n\x08position\x18\x02 \x01(\x0b\x32\x10.ledmon.Position\x12\x11\n\tequipment\x18\x03 \x03(\t\"G\n\x13StorageTransferData\x12\x0c\n\x04item\x18\x01 \x01(\t\x12\"\n\x04mode\x18\x02 \x01(\x0e\x32\x14.ledmon.TransferMode\"\x1c\n\x0bStorageData\x12\r\n\x05items\x18\x01 \x03(\t\"}\n\x10ResearchProgress\x12\x38\n\x08progress\x18\x01 \x03(\x0b\x32&.ledmon.ResearchProgress.ProgressEntry\x1a/\n\rProgressEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\".\n\x0bRecipesData\x12\x1f\n\x07recipes\x18\x01 \x03(\x0b\x32\x0e.ledmon.Recipe\"<\n\x06Recipe\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x13\n\x0bingredients\x18\x04 \x03(\t\x12\x10\n\x08products\x18\x05 \x03(\t\"\x94\x01\n\x0eTradeOfferList\x12\x32\n\x06offers\x18\x01 \x03(\x0b\x32\".ledmon.TradeOfferList.OffersEntry\x12\x0b\n\x03own\x18\x02 \x03(\t\x1a\x41\n\x0bOffersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.ledmon.TradeOffer:\x02\x38\x01\"@\n\nTradeOffer\x12\x0e\n\x06inputs\x18\x01 \x03(\t\x12\x0f\n\x07outputs\x18\x02 \x03(\t\x12\x11\n\tremaining\x18\x03 \x01(\x05\"\x1a\n\x0cTradeOfferId\x12\n\n\x02id\x18\x01 \x01(\t\"\"\n\x12\x43onsumableDuration\x12\x0c\n\x04time\x18\x01 \x01(\x02\"\x1e\n\x0eScoreboardData\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t*I\n\rSessionStatus\x12\x0b\n\x07STARTED\x10\x00\x12\x0c\n\x08\x46INISHED\x10\x01\x12\x11\n\rINVALID_TOKEN\x10\x02\x12\n\n\x06\x44\x45NIED\x10\x03*%\n\x0eMovementResult\x12\x06\n\x02OK\x10\x00\x12\x0b\n\x07\x42LOCKED\x10\x01*;\n\x18InteractionRequestAction\x12\t\n\x05START\x10\x00\x12\x14\n\x10SUBMIT_CHALLENGE\x10\x01*D\n\x19InteractionResponseAction\x12\x0b\n\x07SUCCESS\x10\x00\x12\x0b\n\x07\x46\x41ILURE\x10\x01\x12\r\n\tCHALLENGE\x10\x02**\n\x0c\x41\x63tionResult\x12\x0e\n\nSUCCESSFUL\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01*%\n\x0cTransferMode\x12\x08\n\x04TAKE\x10\x00\x12\x0b\n\x07\x44\x45POSIT\x10\x01\x32\xa2\x0f\n\x05World\x12*\n\x04Ping\x12\r.ledmon.Empty\x1a\x11.ledmon.PingReply\"\x00\x12\x32\n\nPingStream\x12\r.ledmon.Empty\x1a\x11.ledmon.PingReply\"\x00\x30\x01\x12.\n\nGetMapInfo\x12\r.ledmon.Empty\x1a\x0f.ledmon.MapInfo\"\x00\x12;\n\x07Session\x12\x16.ledmon.SessionRequest\x1a\x14.ledmon.SessionReply\"\x00\x30\x01\x12+\n\tKeepAlive\x12\r.ledmon.Empty\x1a\r.ledmon.Empty\"\x00\x12/\n\x08GetState\x12\r.ledmon.Empty\x1a\x12.ledmon.StateReply\"\x00\x12\x37\n\x0eGetStateStream\x12\r.ledmon.Empty\x1a\x12.ledmon.StateReply\"\x00\x30\x01\x12\x38\n\rGetScoreboard\x12\r.ledmon.Empty\x1a\x16.ledmon.ScoreboardData\"\x00\x12\x38\n\x0bMoveForward\x12\r.ledmon.Empty\x1a\x18.ledmon.MovementResponse\"\x00\x12\x39\n\x0cMoveBackward\x12\r.ledmon.Empty\x1a\x18.ledmon.MovementResponse\"\x00\x12\x35\n\x08TurnLeft\x12\r.ledmon.Empty\x1a\x18.ledmon.MovementResponse\"\x00\x12\x36\n\tTurnRight\x12\r.ledmon.Empty\x1a\x18.ledmon.MovementResponse\"\x00\x12\x37\n\nTurnAround\x12\r.ledmon.Empty\x1a\x18.ledmon.MovementResponse\"\x00\x12I\n\x08Interact\x12\x1a.ledmon.InteractionRequest\x1a\x1b.ledmon.InteractionResponse\"\x00(\x01\x30\x01\x12\x34\n\x05\x43raft\x12\x11.ledmon.CraftData\x1a\x16.ledmon.ActionResponse\"\x00\x12H\n\x0fStorageTransfer\x12\x1b.ledmon.StorageTransferData\x1a\x16.ledmon.ActionResponse\"\x00\x12\x33\n\x0bStorageList\x12\r.ledmon.Empty\x1a\x13.ledmon.StorageData\"\x00\x12\x36\n\x08Research\x12\x10.ledmon.ItemInfo\x1a\x16.ledmon.ActionResponse\"\x00\x12\x33\n\x05Scrap\x12\x10.ledmon.ItemInfo\x1a\x16.ledmon.ActionResponse\"\x00\x12@\n\x13GetResearchProgress\x12\r.ledmon.Empty\x1a\x18.ledmon.ResearchProgress\"\x00\x12\x32\n\nGetRecipes\x12\r.ledmon.Empty\x1a\x13.ledmon.RecipesData\"\x00\x12:\n\x0fListTradeOffers\x12\r.ledmon.Empty\x1a\x16.ledmon.TradeOfferList\"\x00\x12>\n\x10\x43reateTradeOffer\x12\x12.ledmon.TradeOffer\x1a\x14.ledmon.TradeOfferId\"\x00\x12\x42\n\x10\x41\x63\x63\x65ptTradeOffer\x12\x14.ledmon.TradeOfferId\x1a\x16.ledmon.ActionResponse\"\x00\x12\x39\n\x10\x43\x61ncelTradeOffer\x12\x14.ledmon.TradeOfferId\x1a\r.ledmon.Empty\"\x00\x12\x31\n\tSetAvatar\x12\x13.ledmon.AvatarIndex\x1a\r.ledmon.Empty\"\x00\x12\x36\n\x0cGetInventory\x12\r.ledmon.Empty\x1a\x15.ledmon.InventoryData\"\x00\x12\x38\n\tEquipItem\x12\x11.ledmon.EquipInfo\x1a\x16.ledmon.ActionResponse\"\x00\x12<\n\x0bUnequipItem\x12\x13.ledmon.UnequipInfo\x1a\x16.ledmon.ActionResponse\"\x00\x12\x31\n\tGetHealth\x12\r.ledmon.Empty\x1a\x13.ledmon.HealthCount\"\x00\x12\x31\n\x06\x41ttack\x12\r.ledmon.Empty\x1a\x16.ledmon.ActionResponse\"\x00\x12\x39\n\x0b\x43onsumeItem\x12\x10.ledmon.ItemInfo\x1a\x16.ledmon.ActionResponse\"\x00\x12M\n\x1eGetRemainingConsumableDuration\x12\r.ledmon.Empty\x1a\x1a.ledmon.ConsumableDuration\"\x00\x12-\n\x04Look\x12\r.ledmon.Empty\x1a\x14.ledmon.LookResponse\"\x00\x62\x06proto3"
|
9
9
|
|
10
10
|
pool = ::Google::Protobuf::DescriptorPool.generated_pool
|
11
11
|
pool.add_serialized_file(descriptor_data)
|
@@ -35,6 +35,8 @@ module Ledmon
|
|
35
35
|
StorageTransferData = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("ledmon.StorageTransferData").msgclass
|
36
36
|
StorageData = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("ledmon.StorageData").msgclass
|
37
37
|
ResearchProgress = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("ledmon.ResearchProgress").msgclass
|
38
|
+
RecipesData = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("ledmon.RecipesData").msgclass
|
39
|
+
Recipe = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("ledmon.Recipe").msgclass
|
38
40
|
TradeOfferList = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("ledmon.TradeOfferList").msgclass
|
39
41
|
TradeOffer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("ledmon.TradeOffer").msgclass
|
40
42
|
TradeOfferId = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("ledmon.TradeOfferId").msgclass
|
@@ -34,6 +34,7 @@ module Ledmon
|
|
34
34
|
rpc :Research, ::Ledmon::ItemInfo, ::Ledmon::ActionResponse
|
35
35
|
rpc :Scrap, ::Ledmon::ItemInfo, ::Ledmon::ActionResponse
|
36
36
|
rpc :GetResearchProgress, ::Ledmon::Empty, ::Ledmon::ResearchProgress
|
37
|
+
rpc :GetRecipes, ::Ledmon::Empty, ::Ledmon::RecipesData
|
37
38
|
rpc :ListTradeOffers, ::Ledmon::Empty, ::Ledmon::TradeOfferList
|
38
39
|
rpc :CreateTradeOffer, ::Ledmon::TradeOffer, ::Ledmon::TradeOfferId
|
39
40
|
rpc :AcceptTradeOffer, ::Ledmon::TradeOfferId, ::Ledmon::ActionResponse
|
data/lib/ledmon.rb
CHANGED
data/protos/world.proto
CHANGED
@@ -29,6 +29,8 @@ service World {
|
|
29
29
|
rpc Research (ItemInfo) returns (ActionResponse) {}
|
30
30
|
rpc Scrap (ItemInfo) returns (ActionResponse) {}
|
31
31
|
rpc GetResearchProgress (Empty) returns (ResearchProgress) {}
|
32
|
+
rpc GetRecipes (Empty) returns (RecipesData) {}
|
33
|
+
|
32
34
|
rpc ListTradeOffers (Empty) returns (TradeOfferList) {}
|
33
35
|
rpc CreateTradeOffer (TradeOffer) returns (TradeOfferId) {}
|
34
36
|
rpc AcceptTradeOffer (TradeOfferId) returns (ActionResponse) {}
|
@@ -86,6 +88,7 @@ message AvatarIndex{
|
|
86
88
|
message SessionReply {
|
87
89
|
SessionStatus status = 1;
|
88
90
|
string name = 2;
|
91
|
+
optional MovementResponse movement = 3;
|
89
92
|
}
|
90
93
|
|
91
94
|
enum SessionStatus {
|
@@ -114,6 +117,7 @@ message MovementResponse {
|
|
114
117
|
MovementResult result = 1;
|
115
118
|
optional Position position = 2;
|
116
119
|
float sleep_time = 3;
|
120
|
+
optional string heading = 4;
|
117
121
|
}
|
118
122
|
|
119
123
|
enum InteractionRequestAction {
|
@@ -194,7 +198,15 @@ message StorageData{
|
|
194
198
|
repeated string items = 1;
|
195
199
|
}
|
196
200
|
message ResearchProgress{
|
197
|
-
map<string,
|
201
|
+
map<string, float> progress = 1;
|
202
|
+
}
|
203
|
+
message RecipesData{
|
204
|
+
repeated Recipe recipes = 1;
|
205
|
+
}
|
206
|
+
message Recipe {
|
207
|
+
string key = 1;
|
208
|
+
repeated string ingredients = 4;
|
209
|
+
repeated string products = 5;
|
198
210
|
}
|
199
211
|
message TradeOfferList{
|
200
212
|
map<string, TradeOffer> offers = 1;
|
@@ -213,4 +225,4 @@ message ConsumableDuration{
|
|
213
225
|
}
|
214
226
|
message ScoreboardData{
|
215
227
|
string data = 1;
|
216
|
-
}
|
228
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ledmon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ahmed Al Hafoudh
|
@@ -149,6 +149,48 @@ dependencies:
|
|
149
149
|
- - "~>"
|
150
150
|
- !ruby/object:Gem::Version
|
151
151
|
version: 0.23.1
|
152
|
+
- !ruby/object:Gem::Dependency
|
153
|
+
name: redcarpet
|
154
|
+
requirement: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '3.6'
|
159
|
+
type: :runtime
|
160
|
+
prerelease: false
|
161
|
+
version_requirements: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '3.6'
|
166
|
+
- !ruby/object:Gem::Dependency
|
167
|
+
name: rouge
|
168
|
+
requirement: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '4.0'
|
173
|
+
type: :runtime
|
174
|
+
prerelease: false
|
175
|
+
version_requirements: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - "~>"
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '4.0'
|
180
|
+
- !ruby/object:Gem::Dependency
|
181
|
+
name: launchy
|
182
|
+
requirement: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - "~>"
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '3.1'
|
187
|
+
type: :runtime
|
188
|
+
prerelease: false
|
189
|
+
version_requirements: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - "~>"
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '3.1'
|
152
194
|
- !ruby/object:Gem::Dependency
|
153
195
|
name: grpc-tools
|
154
196
|
requirement: !ruby/object:Gem::Requirement
|
@@ -175,6 +217,8 @@ extra_rdoc_files: []
|
|
175
217
|
files:
|
176
218
|
- ".rspec"
|
177
219
|
- ".ruby-version"
|
220
|
+
- CLAUDE.md
|
221
|
+
- DOCS.md
|
178
222
|
- LICENSE.txt
|
179
223
|
- Makefile
|
180
224
|
- README.md
|