hytale 0.1.0 → 0.1.2
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/README.md +224 -9
- data/lib/hytale/client/launcher_log/launcher_log_session.rb +3 -1
- data/lib/hytale/client/launcher_log.rb +8 -3
- data/lib/hytale/client/map/chunk.rb +11 -9
- data/lib/hytale/client/map/renderer.rb +1 -3
- data/lib/hytale/client/player/death_position.rb +47 -0
- data/lib/hytale/client/player/inventory.rb +9 -1
- data/lib/hytale/client/player/item_storage.rb +8 -0
- data/lib/hytale/client/player/respawn_point.rb +43 -0
- data/lib/hytale/client/player.rb +74 -2
- data/lib/hytale/client/settings.rb +0 -7
- data/lib/hytale/client/zone/region.rb +52 -0
- data/lib/hytale/client/zone.rb +68 -0
- data/lib/hytale/server/process.rb +3 -0
- data/lib/hytale/version.rb +1 -1
- data/lib/hytale.rb +1 -0
- metadata +20 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c1ecc8d6da6ef59f252740739b05fad04f49e0a6cd628c94a085a6dbd43cb918
|
|
4
|
+
data.tar.gz: 804efc4f07dc64ac5a68ba5d28043c1ac0094f6c42ba6cf1734c7f1c985b4380
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a1be72b9c7373e5fa9b682758b5b756384d25350df8b14fc5bdb555a09f9577f93ecd50b297b56c436e94dee76872c2d6972316d6b202f4b9ada06b335980aec
|
|
7
|
+
data.tar.gz: e73dc31ff553991792fafbc611d58c037770af922366075e27a1982294eb90618c58fb89cd38d552bfbcc394084f3a24f0eb0f163bf4f73e826a2f4604c8647d
|
data/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<p>
|
|
6
6
|
<a href="https://rubygems.org/gems/hytale"><img alt="Gem Version" src="https://img.shields.io/gem/v/hytale"></a>
|
|
7
|
-
<a href="https://github.com/marcoroth/hytale-ruby/blob/main/LICENSE.txt"><img alt="License" src="https://img.shields.io/github/license/marcoroth/hytale"></a>
|
|
7
|
+
<a href="https://github.com/marcoroth/hytale-ruby/blob/main/LICENSE.txt"><img alt="License" src="https://img.shields.io/github/license/marcoroth/hytale-ruby"></a>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
10
|
<p>Read and parse Hytale game data including settings, saves, players, and launcher logs.<br/>Cross-platform support for macOS, Windows, and Linux.</p>
|
|
@@ -295,10 +295,10 @@ save = Hytale.client.save("New World")
|
|
|
295
295
|
player = save.players.first
|
|
296
296
|
|
|
297
297
|
player.name # => "marcoroth"
|
|
298
|
-
player.uuid # => "
|
|
298
|
+
player.uuid # => "00000000-0000-0000-0000-000000000000"
|
|
299
299
|
player.position # => (590.75, 123.0, 374.2)
|
|
300
300
|
player.game_mode # => "Adventure"
|
|
301
|
-
player.discovered_zones # => [
|
|
301
|
+
player.discovered_zones # => [Zone::Region, Zone::Region, ...]
|
|
302
302
|
player.skin # => PlayerSkin object
|
|
303
303
|
player.avatar_preview_path # => "/path/to/CachedAvatarPreviews/uuid.png"
|
|
304
304
|
```
|
|
@@ -333,10 +333,24 @@ end
|
|
|
333
333
|
|------|-------------|
|
|
334
334
|
| `hotbar` | 9-slot quick access bar |
|
|
335
335
|
| `storage` | Main inventory (36 slots) |
|
|
336
|
+
| `backpack` | Optional backpack storage (if equipped) |
|
|
336
337
|
| `armor` | Head, chest, hands, legs |
|
|
337
338
|
| `utility` | Utility items (4 slots) |
|
|
338
339
|
| `tools` | Builder/editor tools |
|
|
339
340
|
|
|
341
|
+
**Check if player has a backpack:**
|
|
342
|
+
|
|
343
|
+
```ruby
|
|
344
|
+
player.inventory.backpack? # => true/false
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**ItemStorage type checks:**
|
|
348
|
+
|
|
349
|
+
```ruby
|
|
350
|
+
player.inventory.backpack.empty? # => true (type is "Empty" - no backpack equipped)
|
|
351
|
+
player.inventory.backpack.simple? # => true (type is "Simple" - backpack equipped)
|
|
352
|
+
```
|
|
353
|
+
|
|
340
354
|
**Item properties:**
|
|
341
355
|
|
|
342
356
|
```ruby
|
|
@@ -349,6 +363,130 @@ item.durability_percent # => 14.9
|
|
|
349
363
|
item.damaged? # => true
|
|
350
364
|
```
|
|
351
365
|
|
|
366
|
+
**Respawn points:**
|
|
367
|
+
|
|
368
|
+
```ruby
|
|
369
|
+
player.respawn_points.each do |point|
|
|
370
|
+
puts "#{point.name} at #{point.position}"
|
|
371
|
+
end
|
|
372
|
+
# => Kweebec village at (-2150.5, 119.05, -403.1)
|
|
373
|
+
# => Bed at (-795.1, 121.05, 29.47)
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Death positions:**
|
|
377
|
+
|
|
378
|
+
```ruby
|
|
379
|
+
player.death_positions.each do |death|
|
|
380
|
+
puts "Died on day #{death.day} at #{death.position}"
|
|
381
|
+
end
|
|
382
|
+
# => Died on day 68 at (-677.67, 27.99, -153.48)
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Discovered instances (dungeons, locations):**
|
|
386
|
+
|
|
387
|
+
```ruby
|
|
388
|
+
player.discovered_instances
|
|
389
|
+
# => ["4781d0dd-5370-4962-a1fc-521ec7ff3e23", ...]
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Player state:**
|
|
393
|
+
|
|
394
|
+
```ruby
|
|
395
|
+
player.flying? # => false
|
|
396
|
+
player.first_spawn? # => false
|
|
397
|
+
player.head_rotation # => Rotation object (separate from body)
|
|
398
|
+
player.current_world # => "default"
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Saved hotbars:**
|
|
402
|
+
|
|
403
|
+
```ruby
|
|
404
|
+
player.saved_hotbars # => [ItemStorage, ...]
|
|
405
|
+
player.current_hotbar_index # => 0
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**Progress tracking:**
|
|
409
|
+
|
|
410
|
+
```ruby
|
|
411
|
+
player.known_recipes # => []
|
|
412
|
+
player.unique_item_usages # => ["Upgrade_Backpack_1"]
|
|
413
|
+
player.active_objectives # => []
|
|
414
|
+
player.reputation_data # => {}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Zones and Regions
|
|
418
|
+
|
|
419
|
+
Hytale organizes the world into zones (biomes) and regions (areas within zones):
|
|
420
|
+
|
|
421
|
+
**Zones (biomes):**
|
|
422
|
+
|
|
423
|
+
**List all zones (requires game to be installed):**
|
|
424
|
+
|
|
425
|
+
```ruby
|
|
426
|
+
Hytale::Client::Zone.all
|
|
427
|
+
# => [#<Zone id="Emerald_Wilds">, #<Zone id="Howling_Sands">, ...]
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Find a specific zone:**
|
|
431
|
+
|
|
432
|
+
```ruby
|
|
433
|
+
zone = Hytale::Client::Zone.find("Emerald_Wilds")
|
|
434
|
+
zone.id # => "Emerald_Wilds"
|
|
435
|
+
zone.name # => "Emerald Wilds"
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**Get all regions in a zone:**
|
|
439
|
+
|
|
440
|
+
```ruby
|
|
441
|
+
zone.regions
|
|
442
|
+
# => [#<Zone::Region id="Zone1_Spawn">, #<Zone::Region id="Zone1_Tier1">, ...]
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Regions (areas within zones):**
|
|
446
|
+
|
|
447
|
+
**List all regions:**
|
|
448
|
+
|
|
449
|
+
```ruby
|
|
450
|
+
Hytale::Client::Zone::Region.all
|
|
451
|
+
# => [#<Zone::Region id="Zone1_Spawn">, #<Zone::Region id="Zone1_Tier1">, ...]
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Find a specific region:**
|
|
455
|
+
|
|
456
|
+
```ruby
|
|
457
|
+
region = Hytale::Client::Zone::Region.find("Zone1_Tier1")
|
|
458
|
+
region.id # => "Zone1_Tier1"
|
|
459
|
+
region.name # => "Drifting Plains"
|
|
460
|
+
region.region_name # => "Drifting Plains"
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
**Navigate to parent zone:**
|
|
464
|
+
|
|
465
|
+
```ruby
|
|
466
|
+
region.zone # => #<Zone id="Emerald_Wilds">
|
|
467
|
+
region.zone.name # => "Emerald Wilds"
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
**Player discovered zones:**
|
|
471
|
+
|
|
472
|
+
```ruby
|
|
473
|
+
player.discovered_zones.each do |region|
|
|
474
|
+
puts "#{region.name} (#{region.zone.name})"
|
|
475
|
+
end
|
|
476
|
+
# => First Gate of the Echo (Emerald Wilds)
|
|
477
|
+
# => Drifting Plains (Emerald Wilds)
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
**Zone/Region mapping:**
|
|
481
|
+
|
|
482
|
+
| Zone | Region Prefix | Example Regions |
|
|
483
|
+
|------|---------------|-----------------|
|
|
484
|
+
| Emerald Wilds | Zone1_* | Zone1_Spawn, Zone1_Tier1, Zone1_Tier2, Zone1_Tier3 |
|
|
485
|
+
| Howling Sands | Zone2_* | Zone2_Tier1, Zone2_Tier2, Zone2_Tier3 |
|
|
486
|
+
| Whisperfrost Frontiers | Zone3_* | Zone3_Tier1, Zone3_Tier2, Zone3_Tier3 |
|
|
487
|
+
| Devastated Lands | Zone4_* | Zone4_Tier4, Zone4_Tier5 |
|
|
488
|
+
| Oceans | Oceans | Oceans |
|
|
489
|
+
|
|
352
490
|
### Memories (Discovered Creatures)
|
|
353
491
|
|
|
354
492
|
Track discovered NPCs and creatures:
|
|
@@ -625,8 +763,8 @@ chunk = region.each_chunk.first
|
|
|
625
763
|
|
|
626
764
|
chunk.block_types # => ["Rock_Stone", "Soil_Dirt", "Soil_Grass", ...]
|
|
627
765
|
chunk.terrain_type # => :grassland
|
|
628
|
-
chunk.
|
|
629
|
-
chunk.
|
|
766
|
+
chunk.water? # => false
|
|
767
|
+
chunk.vegetation? # => true
|
|
630
768
|
chunk.local_x # => 15
|
|
631
769
|
chunk.local_z # => 8
|
|
632
770
|
chunk.world_x # => -272
|
|
@@ -793,6 +931,83 @@ process.pid # => 12345
|
|
|
793
931
|
| `player_skins` | List all cached PlayerSkin objects |
|
|
794
932
|
| `player_skin(uuid)` | Find PlayerSkin by UUID |
|
|
795
933
|
|
|
934
|
+
### Hytale::Client::Player
|
|
935
|
+
|
|
936
|
+
| Method | Description |
|
|
937
|
+
|--------|-------------|
|
|
938
|
+
| `name` | Player display name |
|
|
939
|
+
| `uuid` | Player UUID |
|
|
940
|
+
| `position` | Current Position object |
|
|
941
|
+
| `rotation` | Current body Rotation object |
|
|
942
|
+
| `head_rotation` | Current head Rotation object |
|
|
943
|
+
| `velocity` | Current Vector3 velocity |
|
|
944
|
+
| `stats` | EntityStats object (health, stamina, etc.) |
|
|
945
|
+
| `inventory` | Inventory object |
|
|
946
|
+
| `game_mode` | Current game mode ("Adventure", "Creative", etc.) |
|
|
947
|
+
| `current_world` | Current world name |
|
|
948
|
+
| `discovered_zones` | Array of Zone::Region objects |
|
|
949
|
+
| `discovered_instances` | Array of discovered dungeon/location UUIDs |
|
|
950
|
+
| `respawn_points` | Array of RespawnPoint objects |
|
|
951
|
+
| `death_positions` | Array of DeathPosition objects |
|
|
952
|
+
| `memories` | Array of PlayerMemory objects |
|
|
953
|
+
| `known_recipes` | Array of learned recipe IDs |
|
|
954
|
+
| `unique_item_usages` | Array of used item IDs (upgrades, etc.) |
|
|
955
|
+
| `active_objectives` | Array of active quest UUIDs |
|
|
956
|
+
| `reputation_data` | Hash of faction reputations |
|
|
957
|
+
| `saved_hotbars` | Array of saved ItemStorage hotbars |
|
|
958
|
+
| `current_hotbar_index` | Currently selected hotbar slot |
|
|
959
|
+
| `flying?` | Is player currently flying |
|
|
960
|
+
| `first_spawn?` | Has player spawned before |
|
|
961
|
+
| `skin` | PlayerSkin object |
|
|
962
|
+
| `avatar_preview_path` | Path to cached avatar image |
|
|
963
|
+
|
|
964
|
+
### Hytale::Client::Player::RespawnPoint
|
|
965
|
+
|
|
966
|
+
| Method | Description |
|
|
967
|
+
|--------|-------------|
|
|
968
|
+
| `name` | Respawn point name (e.g., "Ria's bed") |
|
|
969
|
+
| `position` | Exact respawn Position |
|
|
970
|
+
| `block_position` | Block coordinates Position |
|
|
971
|
+
| `x`, `y`, `z` | Shortcut position accessors |
|
|
972
|
+
|
|
973
|
+
### Hytale::Client::Player::DeathPosition
|
|
974
|
+
|
|
975
|
+
| Method | Description |
|
|
976
|
+
|--------|-------------|
|
|
977
|
+
| `marker_id` | Death marker UUID |
|
|
978
|
+
| `day` | Game day of death |
|
|
979
|
+
| `position` | Death Position object |
|
|
980
|
+
| `rotation` | Death Rotation object |
|
|
981
|
+
| `x`, `y`, `z` | Shortcut position accessors |
|
|
982
|
+
|
|
983
|
+
### Hytale::Client::Zone
|
|
984
|
+
|
|
985
|
+
| Method | Description |
|
|
986
|
+
|--------|-------------|
|
|
987
|
+
| `all` | List all Zone objects (from locale) |
|
|
988
|
+
| `find(id)` | Find Zone by ID, returns nil if not found |
|
|
989
|
+
| `new(id)` | Create a Zone::Base instance |
|
|
990
|
+
|
|
991
|
+
### Hytale::Client::Zone::Base
|
|
992
|
+
|
|
993
|
+
| Method | Description |
|
|
994
|
+
|--------|-------------|
|
|
995
|
+
| `id` | Zone ID (e.g., "Emerald_Wilds") |
|
|
996
|
+
| `name` | Translated zone name (e.g., "Emerald Wilds") |
|
|
997
|
+
| `regions` | All Region objects belonging to this zone |
|
|
998
|
+
|
|
999
|
+
### Hytale::Client::Zone::Region
|
|
1000
|
+
|
|
1001
|
+
| Method | Description |
|
|
1002
|
+
|--------|-------------|
|
|
1003
|
+
| `all` | List all Region objects (from locale) |
|
|
1004
|
+
| `find(id)` | Find Region by ID, returns nil if not found |
|
|
1005
|
+
| `id` | Region ID (e.g., "Zone1_Tier1") |
|
|
1006
|
+
| `name` | Translated region name (e.g., "Drifting Plains") |
|
|
1007
|
+
| `region_name` | Same as `name` |
|
|
1008
|
+
| `zone` | Parent Zone::Base object |
|
|
1009
|
+
| `zone_name` | Parent zone's translated name |
|
|
1010
|
+
|
|
796
1011
|
### Hytale::Client::Map
|
|
797
1012
|
|
|
798
1013
|
| Method | Description |
|
|
@@ -839,8 +1054,8 @@ process.pid # => 12345
|
|
|
839
1054
|
| `block_types` | Block type IDs found in chunk |
|
|
840
1055
|
| `block_palette` | Parsed palette (index → block name) |
|
|
841
1056
|
| `terrain_type` | Detected terrain (`:grassland`, `:water`, etc.) |
|
|
842
|
-
| `
|
|
843
|
-
| `
|
|
1057
|
+
| `water?` | Contains water blocks |
|
|
1058
|
+
| `vegetation?` | Contains plant/grass blocks |
|
|
844
1059
|
| `to_ascii_map` | 16x16 ASCII representation |
|
|
845
1060
|
|
|
846
1061
|
### Hytale::Client::Map::Block
|
|
@@ -1169,8 +1384,8 @@ Hytale.client.player_skins
|
|
|
1169
1384
|
**Find a specific skin:**
|
|
1170
1385
|
|
|
1171
1386
|
```ruby
|
|
1172
|
-
skin = Hytale.client.player_skin("
|
|
1173
|
-
skin.uuid # => "
|
|
1387
|
+
skin = Hytale.client.player_skin("00000000-0000-0000-0000-000000000000")
|
|
1388
|
+
skin.uuid # => "00000000-0000-0000-0000-000000000000"
|
|
1174
1389
|
```
|
|
1175
1390
|
|
|
1176
1391
|
**Appearance:**
|
|
@@ -24,7 +24,9 @@ module Hytale
|
|
|
24
24
|
def profile_uuid
|
|
25
25
|
profile_entry = entries.find { |e| e.message&.include?("setting current profile") }
|
|
26
26
|
|
|
27
|
-
profile_entry
|
|
27
|
+
return nil unless profile_entry
|
|
28
|
+
|
|
29
|
+
profile_entry.message&.match(/to (\S+)/)&.[](1)
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
def game_launched?
|
|
@@ -48,12 +48,18 @@ module Hytale
|
|
|
48
48
|
|
|
49
49
|
def current_profile_uuid
|
|
50
50
|
profile_entry = entries.reverse.find { |e| e.message&.include?("setting current profile") }
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
return nil unless profile_entry
|
|
53
|
+
|
|
54
|
+
profile_entry.message&.match(/to (\S+)/)&.[](1)
|
|
52
55
|
end
|
|
53
56
|
|
|
54
57
|
def current_channel
|
|
55
58
|
channel_entry = entries.reverse.find { |e| e.message&.include?("setting channel") }
|
|
56
|
-
|
|
59
|
+
|
|
60
|
+
return nil unless channel_entry
|
|
61
|
+
|
|
62
|
+
channel_entry.attributes&.[]("channel")
|
|
57
63
|
end
|
|
58
64
|
|
|
59
65
|
def last_game_launch
|
|
@@ -61,7 +67,6 @@ module Hytale
|
|
|
61
67
|
end
|
|
62
68
|
|
|
63
69
|
def sessions
|
|
64
|
-
# Group entries by launcher start
|
|
65
70
|
sessions = []
|
|
66
71
|
current_session = nil
|
|
67
72
|
|
|
@@ -63,26 +63,26 @@ module Hytale
|
|
|
63
63
|
@block_palette ||= extract_palette
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
def
|
|
66
|
+
def block?(block_type)
|
|
67
67
|
block_types.include?(block_type)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
def
|
|
70
|
+
def water?
|
|
71
71
|
block_types.any? { |t| t.include?("Water") }
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
def
|
|
74
|
+
def vegetation?
|
|
75
75
|
block_types.any? { |t| t.include?("Plant") || t.include?("Grass") || t.include?("Tree") }
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def terrain_type
|
|
79
|
-
if
|
|
79
|
+
if water?
|
|
80
80
|
:water
|
|
81
81
|
elsif block_types.any? { |t| t.include?("Sand") }
|
|
82
82
|
:desert
|
|
83
83
|
elsif block_types.any? { |t| t.include?("Snow") || t.include?("Ice") }
|
|
84
84
|
:snow
|
|
85
|
-
elsif
|
|
85
|
+
elsif vegetation?
|
|
86
86
|
:grassland
|
|
87
87
|
else
|
|
88
88
|
:rocky
|
|
@@ -195,9 +195,7 @@ module Hytale
|
|
|
195
195
|
def cache_path(texture_scale: 16, shading: true)
|
|
196
196
|
return nil unless region
|
|
197
197
|
|
|
198
|
-
save_name = region.path.split("/").find
|
|
199
|
-
p.include?("Saves")
|
|
200
|
-
end&.then { |_| region.path.split("Saves/")[1]&.split("/")&.first } || "unknown"
|
|
198
|
+
save_name = region.path.split("/").find { |p| p.include?("Saves") }&.then { |_| region.path.split("Saves/")[1]&.split("/")&.first } || "unknown"
|
|
201
199
|
world_name = region.path.split("/worlds/")[1]&.split("/")&.first || "default"
|
|
202
200
|
|
|
203
201
|
cache_dir = File.join(
|
|
@@ -217,14 +215,17 @@ module Hytale
|
|
|
217
215
|
|
|
218
216
|
def cached?(texture_scale: 16, shading: true)
|
|
219
217
|
path = cache_path(texture_scale: texture_scale, shading: shading)
|
|
218
|
+
|
|
220
219
|
path && File.exist?(path)
|
|
221
220
|
end
|
|
222
221
|
|
|
223
222
|
def clear_cache!
|
|
224
223
|
path = cache_path
|
|
224
|
+
|
|
225
225
|
return unless path
|
|
226
226
|
|
|
227
227
|
dir = File.dirname(path)
|
|
228
|
+
|
|
228
229
|
FileUtils.rm_rf(dir) if File.directory?(dir)
|
|
229
230
|
end
|
|
230
231
|
|
|
@@ -238,6 +239,7 @@ module Hytale
|
|
|
238
239
|
return nil unless type_id
|
|
239
240
|
|
|
240
241
|
block_type = get_or_create_block_type(type_id)
|
|
242
|
+
|
|
241
243
|
Block.new(block_type, x: x, y: y, z: z, chunk: self)
|
|
242
244
|
end
|
|
243
245
|
|
|
@@ -643,7 +645,7 @@ module Hytale
|
|
|
643
645
|
index_position = position + 1 + length + 2
|
|
644
646
|
index = begin
|
|
645
647
|
search_data[index_position].ord
|
|
646
|
-
rescue StandardError
|
|
648
|
+
rescue StandardError # rubocop:disable Metrics/BlockNesting
|
|
647
649
|
nil
|
|
648
650
|
end
|
|
649
651
|
|
|
@@ -415,12 +415,10 @@ module Hytale
|
|
|
415
415
|
ChunkyPNG::Color.rgb(194, 178, 128)
|
|
416
416
|
when /Snow/, /Ice/
|
|
417
417
|
ChunkyPNG::Color.rgb(240, 240, 255)
|
|
418
|
-
when /Dirt/
|
|
418
|
+
when /Dirt/, /Wood/
|
|
419
419
|
ChunkyPNG::Color.rgb(139, 90, 43)
|
|
420
420
|
when /Stone/, /Rock/
|
|
421
421
|
ChunkyPNG::Color.rgb(128, 128, 128)
|
|
422
|
-
when /Wood/
|
|
423
|
-
ChunkyPNG::Color.rgb(139, 90, 43)
|
|
424
422
|
when /Plant/
|
|
425
423
|
ChunkyPNG::Color.rgb(34, 139, 34)
|
|
426
424
|
when /Ore/
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hytale
|
|
4
|
+
module Client
|
|
5
|
+
class Player
|
|
6
|
+
class DeathPosition
|
|
7
|
+
attr_reader :data
|
|
8
|
+
|
|
9
|
+
def initialize(data)
|
|
10
|
+
@data = data
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def marker_id
|
|
14
|
+
data["MarkerId"]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def day
|
|
18
|
+
data["Day"]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def position
|
|
22
|
+
transform = data["Transform"] || {}
|
|
23
|
+
|
|
24
|
+
Position.new(transform["X"], transform["Y"], transform["Z"])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def rotation
|
|
28
|
+
transform = data["Transform"] || {}
|
|
29
|
+
|
|
30
|
+
Rotation.new(transform["Pitch"], transform["Yaw"], transform["Roll"])
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def x = position.x
|
|
34
|
+
def y = position.y
|
|
35
|
+
def z = position.z
|
|
36
|
+
|
|
37
|
+
def to_s
|
|
38
|
+
"Death on day #{day} at #{position}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def inspect
|
|
42
|
+
"#<DeathPosition day=#{day} position=#{position}>"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -16,6 +16,10 @@ module Hytale
|
|
|
16
16
|
@storage ||= ItemStorage.new(data["Storage"] || {})
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
def backpack
|
|
20
|
+
@backpack ||= ItemStorage.new(data["Backpack"] || {})
|
|
21
|
+
end
|
|
22
|
+
|
|
19
23
|
def hotbar
|
|
20
24
|
@hotbar ||= ItemStorage.new(data["HotBar"] || {})
|
|
21
25
|
end
|
|
@@ -35,8 +39,12 @@ module Hytale
|
|
|
35
39
|
def active_hotbar_slot = data["ActiveHotbarSlot"]
|
|
36
40
|
def sort_type = data["SortType"]
|
|
37
41
|
|
|
42
|
+
def backpack?
|
|
43
|
+
backpack&.simple?
|
|
44
|
+
end
|
|
45
|
+
|
|
38
46
|
def all_items
|
|
39
|
-
[storage, hotbar, armor, utility, tools].flat_map(&:items)
|
|
47
|
+
[storage, backpack, hotbar, armor, utility, tools].flat_map(&:items)
|
|
40
48
|
end
|
|
41
49
|
|
|
42
50
|
def to_h = data
|
|
@@ -13,6 +13,14 @@ module Hytale
|
|
|
13
13
|
def capacity = data["Capacity"]
|
|
14
14
|
def type = data["Id"]
|
|
15
15
|
|
|
16
|
+
def empty?
|
|
17
|
+
type == "Empty"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def simple?
|
|
21
|
+
type == "Simple"
|
|
22
|
+
end
|
|
23
|
+
|
|
16
24
|
def items
|
|
17
25
|
(data["Items"] || {}).map do |slot, item_data|
|
|
18
26
|
Item.new(item_data, slot: slot.to_i)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hytale
|
|
4
|
+
module Client
|
|
5
|
+
class Player
|
|
6
|
+
class RespawnPoint
|
|
7
|
+
attr_reader :data
|
|
8
|
+
|
|
9
|
+
def initialize(data)
|
|
10
|
+
@data = data
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def name
|
|
14
|
+
data["Name"]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def position
|
|
18
|
+
pos = data["RespawnPosition"] || {}
|
|
19
|
+
|
|
20
|
+
Position.new(pos["X"], pos["Y"], pos["Z"])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def block_position
|
|
24
|
+
pos = data["BlockPosition"] || {}
|
|
25
|
+
|
|
26
|
+
Position.new(pos["X"], pos["Y"], pos["Z"])
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def x = position.x
|
|
30
|
+
def y = position.y
|
|
31
|
+
def z = position.z
|
|
32
|
+
|
|
33
|
+
def to_s
|
|
34
|
+
"#{name} at #{position}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def inspect
|
|
38
|
+
"#<RespawnPoint name=#{name.inspect} position=#{position}>"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/hytale/client/player.rb
CHANGED
|
@@ -22,12 +22,14 @@ module Hytale
|
|
|
22
22
|
def position
|
|
23
23
|
transform = components["Transform"] || {}
|
|
24
24
|
pos = transform["Position"] || {}
|
|
25
|
+
|
|
25
26
|
Position.new(pos["X"], pos["Y"], pos["Z"])
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
def rotation
|
|
29
30
|
transform = components["Transform"] || {}
|
|
30
31
|
rot = transform["Rotation"] || {}
|
|
32
|
+
|
|
31
33
|
Rotation.new(rot["Pitch"], rot["Yaw"], rot["Roll"])
|
|
32
34
|
end
|
|
33
35
|
|
|
@@ -57,11 +59,27 @@ module Hytale
|
|
|
57
59
|
end
|
|
58
60
|
|
|
59
61
|
def discovered_zones
|
|
60
|
-
player_data.dig("PlayerData", "DiscoveredZones") || []
|
|
62
|
+
@discovered_zones ||= (player_data.dig("PlayerData", "DiscoveredZones") || []).map do |id|
|
|
63
|
+
Hytale::Client::Zone::Region.new(id)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def discovered_instances
|
|
68
|
+
@discovered_instances ||= (player_data.dig("PlayerData", "DiscoveredInstances") || []).map do |instance|
|
|
69
|
+
decode_binary_uuid(instance)
|
|
70
|
+
end.compact
|
|
61
71
|
end
|
|
62
72
|
|
|
63
73
|
def respawn_points
|
|
64
|
-
player_data.dig("PlayerData", "PerWorldData", "default", "RespawnPoints") || []
|
|
74
|
+
@respawn_points ||= (player_data.dig("PlayerData", "PerWorldData", "default", "RespawnPoints") || []).map do |point|
|
|
75
|
+
RespawnPoint.new(point)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def death_positions
|
|
80
|
+
@death_positions ||= (player_data.dig("PlayerData", "PerWorldData", "default", "DeathPositions") || []).map do |pos|
|
|
81
|
+
DeathPosition.new(pos)
|
|
82
|
+
end
|
|
65
83
|
end
|
|
66
84
|
|
|
67
85
|
def memories
|
|
@@ -70,6 +88,48 @@ module Hytale
|
|
|
70
88
|
end
|
|
71
89
|
end
|
|
72
90
|
|
|
91
|
+
def known_recipes
|
|
92
|
+
player_data.dig("PlayerData", "KnownRecipes") || []
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def unique_item_usages
|
|
96
|
+
components.dig("UniqueItemUsages", "UniqueItemUsed") || []
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def head_rotation
|
|
100
|
+
rot = components.dig("HeadRotation", "Rotation") || {}
|
|
101
|
+
|
|
102
|
+
Rotation.new(rot["Pitch"], rot["Yaw"], rot["Roll"])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def flying?
|
|
106
|
+
player_data.dig("PlayerData", "PerWorldData", "default", "LastMovementStates", "Flying") || false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def first_spawn?
|
|
110
|
+
player_data.dig("PlayerData", "PerWorldData", "default", "FirstSpawn") || false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def active_objectives
|
|
114
|
+
@active_objectives ||= (player_data.dig("PlayerData", "ActiveObjectiveUUIDs") || []).map do |obj|
|
|
115
|
+
decode_binary_uuid(obj)
|
|
116
|
+
end.compact
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def reputation_data
|
|
120
|
+
player_data.dig("PlayerData", "ReputationData") || {}
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def saved_hotbars
|
|
124
|
+
@saved_hotbars ||= (player_data.dig("HotbarManager", "SavedHotbars") || []).compact.map do |hotbar|
|
|
125
|
+
ItemStorage.new(hotbar)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def current_hotbar_index
|
|
130
|
+
player_data.dig("HotbarManager", "CurrentHotbar")
|
|
131
|
+
end
|
|
132
|
+
|
|
73
133
|
def skin
|
|
74
134
|
@skin ||= PlayerSkin.find(uuid)
|
|
75
135
|
end
|
|
@@ -94,6 +154,18 @@ module Hytale
|
|
|
94
154
|
raise ParseError, "Failed to parse player data: #{e.message}"
|
|
95
155
|
end
|
|
96
156
|
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
|
|
160
|
+
def decode_binary_uuid(data)
|
|
161
|
+
return nil unless data.is_a?(Hash) && data["$binary"]
|
|
162
|
+
|
|
163
|
+
bytes = Base64.decode64(data["$binary"])
|
|
164
|
+
return nil unless bytes.length == 16
|
|
165
|
+
|
|
166
|
+
hex = bytes.unpack1("H*")
|
|
167
|
+
"#{hex[0, 8]}-#{hex[8, 4]}-#{hex[12, 4]}-#{hex[16, 4]}-#{hex[20, 12]}"
|
|
168
|
+
end
|
|
97
169
|
end
|
|
98
170
|
end
|
|
99
171
|
end
|
|
@@ -10,7 +10,6 @@ module Hytale
|
|
|
10
10
|
@path = path
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
# Display settings
|
|
14
13
|
def fullscreen? = data["Fullscreen"]
|
|
15
14
|
def maximized? = data["Maximized"]
|
|
16
15
|
def window_width = data["WindowWidth"]
|
|
@@ -21,12 +20,10 @@ module Hytale
|
|
|
21
20
|
def unlimited_fps? = data["UnlimitedFps"]
|
|
22
21
|
def field_of_view = data["FieldOfView"]
|
|
23
22
|
|
|
24
|
-
# Rendering settings
|
|
25
23
|
def rendering
|
|
26
24
|
@rendering ||= RenderingSettings.new(data["RenderingSettings"] || {})
|
|
27
25
|
end
|
|
28
26
|
|
|
29
|
-
# Input settings
|
|
30
27
|
def input_bindings
|
|
31
28
|
@input_bindings ||= InputBindings.new(data["InputBindings"] || {})
|
|
32
29
|
end
|
|
@@ -35,22 +32,18 @@ module Hytale
|
|
|
35
32
|
@mouse_settings ||= MouseSettings.new(data["MouseSettings"] || {})
|
|
36
33
|
end
|
|
37
34
|
|
|
38
|
-
# Audio settings
|
|
39
35
|
def audio
|
|
40
36
|
@audio ||= AudioSettings.new(data["AudioSettings"] || {})
|
|
41
37
|
end
|
|
42
38
|
|
|
43
|
-
# Gameplay settings
|
|
44
39
|
def gameplay
|
|
45
40
|
@gameplay ||= GameplaySettings.new(data["GameplaySettings"] || {})
|
|
46
41
|
end
|
|
47
42
|
|
|
48
|
-
# Builder tools settings
|
|
49
43
|
def builder_tools
|
|
50
44
|
@builder_tools ||= BuilderToolsSettings.new(data["BuilderToolsSettings"] || {})
|
|
51
45
|
end
|
|
52
46
|
|
|
53
|
-
# UI preferences
|
|
54
47
|
def hide_hud? = data["HideHud"]
|
|
55
48
|
def hide_hotbar? = data["HideHotbar"]
|
|
56
49
|
def hide_compass? = data["HideCompass"]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hytale
|
|
4
|
+
module Client
|
|
5
|
+
module Zone
|
|
6
|
+
class Region
|
|
7
|
+
class << self
|
|
8
|
+
def all
|
|
9
|
+
Locale.regions.keys.map { |id| new(id) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def find(id)
|
|
13
|
+
new(id) if Locale.region_name(id)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_reader :id
|
|
18
|
+
|
|
19
|
+
def initialize(id)
|
|
20
|
+
@id = id
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def name
|
|
24
|
+
Locale.region_name(id) || id
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def zone
|
|
28
|
+
zone_id = REGION_PREFIX_TO_ZONE.find { |prefix, _| id.start_with?(prefix) }&.last
|
|
29
|
+
|
|
30
|
+
Zone.new(zone_id) if zone_id
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_s = name
|
|
34
|
+
def inspect = "#<Zone::Region id=#{id.inspect} name=#{name.inspect}>"
|
|
35
|
+
|
|
36
|
+
def ==(other)
|
|
37
|
+
case other
|
|
38
|
+
when Region then id == other.id
|
|
39
|
+
when String then id == other
|
|
40
|
+
else false
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
alias eql? ==
|
|
45
|
+
|
|
46
|
+
def hash
|
|
47
|
+
id.hash
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hytale
|
|
4
|
+
module Client
|
|
5
|
+
module Zone
|
|
6
|
+
ZONE_TO_REGION_PREFIX = {
|
|
7
|
+
"Emerald_Wilds" => "Zone1",
|
|
8
|
+
"Howling_Sands" => "Zone2",
|
|
9
|
+
"Whisperfrost_Frontiers" => "Zone3",
|
|
10
|
+
"Devastated_Lands" => "Zone4",
|
|
11
|
+
"Oceans" => "Oceans",
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
REGION_PREFIX_TO_ZONE = ZONE_TO_REGION_PREFIX.invert.freeze
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
def all
|
|
18
|
+
Locale.zones.keys.map { |id| new(id) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def find(id)
|
|
22
|
+
new(id) if Locale.zone_name(id)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def new(id)
|
|
26
|
+
Zone::Base.new(id)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Base
|
|
31
|
+
attr_reader :id
|
|
32
|
+
|
|
33
|
+
def initialize(id)
|
|
34
|
+
@id = id
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def name
|
|
38
|
+
Locale.zone_name(id) || id
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def regions
|
|
42
|
+
prefix = ZONE_TO_REGION_PREFIX[id]
|
|
43
|
+
|
|
44
|
+
return [] unless prefix
|
|
45
|
+
|
|
46
|
+
Region.all.select { |region| region.id.start_with?(prefix) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_s = name
|
|
50
|
+
def inspect = "#<Zone id=#{id.inspect} name=#{name.inspect}>"
|
|
51
|
+
|
|
52
|
+
def ==(other)
|
|
53
|
+
case other
|
|
54
|
+
when Base then id == other.id
|
|
55
|
+
when String then id == other
|
|
56
|
+
else false
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
alias eql? ==
|
|
61
|
+
|
|
62
|
+
def hash
|
|
63
|
+
id.hash
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/lib/hytale/version.rb
CHANGED
data/lib/hytale.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hytale
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marco Roth
|
|
@@ -9,6 +9,20 @@ bindir: exe
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: base64
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.3'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.3'
|
|
12
26
|
- !ruby/object:Gem::Dependency
|
|
13
27
|
name: chunky_png
|
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -98,12 +112,14 @@ files:
|
|
|
98
112
|
- lib/hytale/client/npc_memory.rb
|
|
99
113
|
- lib/hytale/client/permissions.rb
|
|
100
114
|
- lib/hytale/client/player.rb
|
|
115
|
+
- lib/hytale/client/player/death_position.rb
|
|
101
116
|
- lib/hytale/client/player/entity_stats.rb
|
|
102
117
|
- lib/hytale/client/player/inventory.rb
|
|
103
118
|
- lib/hytale/client/player/item.rb
|
|
104
119
|
- lib/hytale/client/player/item_storage.rb
|
|
105
120
|
- lib/hytale/client/player/player_memory.rb
|
|
106
121
|
- lib/hytale/client/player/position.rb
|
|
122
|
+
- lib/hytale/client/player/respawn_point.rb
|
|
107
123
|
- lib/hytale/client/player/rotation.rb
|
|
108
124
|
- lib/hytale/client/player/vector3.rb
|
|
109
125
|
- lib/hytale/client/player_skin.rb
|
|
@@ -123,6 +139,8 @@ files:
|
|
|
123
139
|
- lib/hytale/client/world.rb
|
|
124
140
|
- lib/hytale/client/world/client_effects.rb
|
|
125
141
|
- lib/hytale/client/world/death_settings.rb
|
|
142
|
+
- lib/hytale/client/zone.rb
|
|
143
|
+
- lib/hytale/client/zone/region.rb
|
|
126
144
|
- lib/hytale/server.rb
|
|
127
145
|
- lib/hytale/server/process.rb
|
|
128
146
|
- lib/hytale/version.rb
|
|
@@ -150,5 +168,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
150
168
|
requirements: []
|
|
151
169
|
rubygems_version: 4.0.3
|
|
152
170
|
specification_version: 4
|
|
153
|
-
summary: Ruby
|
|
171
|
+
summary: Ruby gem for reading Hytale game data
|
|
154
172
|
test_files: []
|