|
1 | 1 | use valence_equipment::{Equipment, EquipmentInventorySync};
|
2 | 2 | use valence_inventory::player_inventory::PlayerInventory;
|
3 |
| -use valence_inventory::Inventory; |
| 3 | +use valence_inventory::{ClickMode, ClientInventoryState, Inventory, SlotChange}; |
4 | 4 | use valence_server::entity::armor_stand::ArmorStandEntityBundle;
|
5 | 5 | use valence_server::entity::item::ItemEntityBundle;
|
6 | 6 | use valence_server::entity::zombie::ZombieEntityBundle;
|
7 | 7 | use valence_server::entity::{EntityLayerId, Position};
|
8 | 8 | use valence_server::math::DVec3;
|
9 |
| -use valence_server::protocol::packets::play::EntityEquipmentUpdateS2c; |
| 9 | +use valence_server::protocol::packets::play::{ |
| 10 | + ClickSlotC2s, EntityEquipmentUpdateS2c, UpdateSelectedSlotC2s, |
| 11 | +}; |
10 | 12 | use valence_server::{ItemKind, ItemStack};
|
11 | 13 |
|
12 | 14 | use crate::testing::ScenarioSingleClient;
|
@@ -298,7 +300,7 @@ fn test_inventory_sync_from_equipment() {
|
298 | 300 | }
|
299 | 301 |
|
300 | 302 | #[test]
|
301 |
| -fn test_inventory_sync_from_inventory() { |
| 303 | +fn test_equipment_sync_from_inventory() { |
302 | 304 | let ScenarioSingleClient {
|
303 | 305 | mut app,
|
304 | 306 | client,
|
@@ -405,3 +407,137 @@ fn test_equipment_priority_over_inventory() {
|
405 | 407 | ItemStack::new(ItemKind::GoldenChestplate, 1, None)
|
406 | 408 | );
|
407 | 409 | }
|
| 410 | + |
| 411 | +#[test] |
| 412 | +fn test_equipment_change_from_player() { |
| 413 | + let ScenarioSingleClient { |
| 414 | + mut app, |
| 415 | + client, |
| 416 | + mut helper, |
| 417 | + .. |
| 418 | + } = ScenarioSingleClient::new(); |
| 419 | + |
| 420 | + // Process a tick to get past the "on join" logic. |
| 421 | + app.update(); |
| 422 | + helper.clear_received(); |
| 423 | + |
| 424 | + app.world_mut() |
| 425 | + .entity_mut(client) |
| 426 | + .insert(EquipmentInventorySync); |
| 427 | + |
| 428 | + let mut player_inventory = app |
| 429 | + .world_mut() |
| 430 | + .get_mut::<Inventory>(client) |
| 431 | + .expect("could not get player equipment"); |
| 432 | + |
| 433 | + player_inventory.set_slot(36, ItemStack::new(ItemKind::DiamondChestplate, 1, None)); |
| 434 | + app.update(); |
| 435 | + helper.clear_received(); |
| 436 | + |
| 437 | + let state_id = app |
| 438 | + .world() |
| 439 | + .get::<ClientInventoryState>(client) |
| 440 | + .expect("could not get player equipment") |
| 441 | + .state_id(); |
| 442 | + |
| 443 | + app.update(); |
| 444 | + |
| 445 | + helper.send(&ClickSlotC2s { |
| 446 | + window_id: 0, |
| 447 | + button: 0, |
| 448 | + mode: ClickMode::Hotbar, |
| 449 | + state_id: state_id.0.into(), |
| 450 | + slot_idx: 36, |
| 451 | + slot_changes: vec![ |
| 452 | + SlotChange { |
| 453 | + idx: 36, |
| 454 | + stack: ItemStack::EMPTY, |
| 455 | + }, |
| 456 | + SlotChange { |
| 457 | + idx: PlayerInventory::SLOT_CHEST as i16, |
| 458 | + stack: ItemStack::new(ItemKind::DiamondChestplate, 1, None), |
| 459 | + }, |
| 460 | + ] |
| 461 | + .into(), |
| 462 | + carried_item: ItemStack::EMPTY, |
| 463 | + }); |
| 464 | + |
| 465 | + app.update(); |
| 466 | + app.update(); |
| 467 | + |
| 468 | + let player_inventory = app |
| 469 | + .world() |
| 470 | + .get::<Inventory>(client) |
| 471 | + .expect("could not get player equipment"); |
| 472 | + |
| 473 | + let player_equipment = app |
| 474 | + .world() |
| 475 | + .get::<Equipment>(client) |
| 476 | + .expect("could not get player equipment"); |
| 477 | + |
| 478 | + assert_eq!( |
| 479 | + player_inventory.slot(PlayerInventory::SLOT_CHEST), |
| 480 | + &ItemStack::new(ItemKind::DiamondChestplate, 1, None) |
| 481 | + ); |
| 482 | + |
| 483 | + assert_eq!(player_inventory.slot(36), &ItemStack::EMPTY); |
| 484 | + |
| 485 | + assert_eq!( |
| 486 | + player_equipment.chest(), |
| 487 | + &ItemStack::new(ItemKind::DiamondChestplate, 1, None) |
| 488 | + ); |
| 489 | +} |
| 490 | + |
| 491 | +#[test] |
| 492 | +fn test_held_item_change_from_client() { |
| 493 | + let ScenarioSingleClient { |
| 494 | + mut app, |
| 495 | + client, |
| 496 | + mut helper, |
| 497 | + .. |
| 498 | + } = ScenarioSingleClient::new(); |
| 499 | + |
| 500 | + // Process a tick to get past the "on join" logic. |
| 501 | + app.update(); |
| 502 | + helper.clear_received(); |
| 503 | + |
| 504 | + app.world_mut() |
| 505 | + .entity_mut(client) |
| 506 | + .insert(EquipmentInventorySync); |
| 507 | + |
| 508 | + let mut player_inventory = app |
| 509 | + .world_mut() |
| 510 | + .get_mut::<Inventory>(client) |
| 511 | + .expect("could not get player equipment"); |
| 512 | + |
| 513 | + player_inventory.set_slot(36, ItemStack::new(ItemKind::DiamondSword, 1, None)); |
| 514 | + player_inventory.set_slot(37, ItemStack::new(ItemKind::IronSword, 1, None)); |
| 515 | + |
| 516 | + app.update(); |
| 517 | + |
| 518 | + let player_equipment = app |
| 519 | + .world() |
| 520 | + .get::<Equipment>(client) |
| 521 | + .expect("could not get player equipment"); |
| 522 | + |
| 523 | + assert_eq!( |
| 524 | + player_equipment.main_hand(), |
| 525 | + &ItemStack::new(ItemKind::DiamondSword, 1, None) |
| 526 | + ); |
| 527 | + |
| 528 | + // Change the held item from the client |
| 529 | + helper.send(&UpdateSelectedSlotC2s { slot: 1 }); |
| 530 | + |
| 531 | + app.update(); // handle change slot |
| 532 | + app.update(); // handle change equipment |
| 533 | + |
| 534 | + let player_equipment = app |
| 535 | + .world() |
| 536 | + .get::<Equipment>(client) |
| 537 | + .expect("could not get player equipment"); |
| 538 | + |
| 539 | + assert_eq!( |
| 540 | + player_equipment.main_hand(), |
| 541 | + &ItemStack::new(ItemKind::IronSword, 1, None) |
| 542 | + ); |
| 543 | +} |
0 commit comments