Skip to content

Commit

Permalink
Load armor and tool properties from pixlyzer item registry
Browse files Browse the repository at this point in the history
  • Loading branch information
stackotter committed May 29, 2024
1 parent 1e2067a commit 4a928b4
Show file tree
Hide file tree
Showing 12 changed files with 332 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ extension Block: BinarySerializable {
fluidState.serialize(into: &buffer)
tint.serialize(into: &buffer)
offset.serialize(into: &buffer)
material.serialize(into: &buffer)
vanillaMaterialIdentifier.serialize(into: &buffer)
physicalMaterial.serialize(into: &buffer)
lightMaterial.serialize(into: &buffer)
soundMaterial.serialize(into: &buffer)
shape.serialize(into: &buffer)
Expand All @@ -54,7 +55,8 @@ extension Block: BinarySerializable {
fluidState: try .deserialize(from: &buffer),
tint: try .deserialize(from: &buffer),
offset: try .deserialize(from: &buffer),
material: try .deserialize(from: &buffer),
vanillaMaterialIdentifier: try .deserialize(from: &buffer),
physicalMaterial: try .deserialize(from: &buffer),
lightMaterial: try .deserialize(from: &buffer),
soundMaterial: try .deserialize(from: &buffer),
shape: try .deserialize(from: &buffer),
Expand Down
15 changes: 15 additions & 0 deletions Sources/Core/Sources/ECS/Components/PlayerInventory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ public class PlayerInventory: Component {
window.slots[Self.offHandIndex]
}

/// The item in the currently selected hotbar slot, `nil` if the slot is empty
/// or the item stack is invalid.
public var mainHandItem: Item? {
guard let stack = hotbar[selectedHotbarSlot].stack else {
return nil
}

guard let item = RegistryStore.shared.itemRegistry.item(withId: stack.itemId) else {
log.warning("Non-existent item with id \(stack.itemId) selected in hotbar")
return nil
}

return item
}

/// Creates the player's inventory state.
/// - Parameter selectedHotbarSlot: Defaults to 0 (the first slot from the left in the main hotbar).
/// - Precondition: The length of `slots` must match ``PlayerInventory/slotCount``.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public struct PlayerAccelerationSystem: System {
z: Int(Foundation.floor(position.z))
)
let block = world.getBlock(at: blockPosition)
let slipperiness = block.material.slipperiness
let slipperiness = block.physicalMaterial.slipperiness

speed = movementSpeed * 0.216 / (slipperiness * slipperiness * slipperiness)
} else if isFlying {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public struct PlayerFrictionSystem: System {
var multiplier: Double = 0.91
if onGround.previousOnGround {
let blockPosition = position.blockUnderneath
let material = world.getBlock(at: blockPosition).material
let material = world.getBlock(at: blockPosition).physicalMaterial

multiplier *= material.slipperiness
}
Expand Down
44 changes: 33 additions & 11 deletions Sources/Core/Sources/ECS/Systems/PlayerInputSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ public final class PlayerInputSystem: System {
suppressInput = try handleChat(event, inputState, guiState)
}

if !suppressInput {
suppressInput = try handleInventory(event, inventory, guiState, eventBus, connection)
}

if !suppressInput {
suppressInput = try handleWindow(event, guiState, eventBus, connection)
}
Expand All @@ -89,17 +93,10 @@ public final class PlayerInputSystem: System {
case .toggleDebugHUD:
guiState.showDebugScreen = !guiState.showDebugScreen
case .toggleInventory:
guiState.showInventory = !guiState.showInventory
if !guiState.showInventory {
// Weirdly enough, the vanilla client sends a close window packet when closing the player's
// inventory even though it never tells the server that it opened the inventory in the first
// place. Likely just for the server to verify the slots and chuck out anything in the crafting
// area.
try inventory.window.close(mouseStack: &guiState.mouseItemStack, eventBus: eventBus, connection: connection)
} else {
inputState.releaseAll()
eventBus.dispatch(ReleaseCursorEvent())
}
// Closing the inventory is handled by `handleInventory`
guiState.showInventory = true
inputState.releaseAll()
eventBus.dispatch(ReleaseCursorEvent())
case .slot1:
inventory.selectedHotbarSlot = 0
case .slot2:
Expand Down Expand Up @@ -282,6 +279,31 @@ public final class PlayerInputSystem: System {
return guiState.showChat
}

/// - Returns: Whether to suppress the input associated with the event or not.
private func handleInventory(
_ event: KeyPressEvent,
_ inventory: PlayerInventory,
_ guiState: GUIStateStorage,
_ eventBus: EventBus,
_ connection: ServerConnection?
) throws -> Bool {
guard guiState.showInventory else {
return false
}

if event.key == .escape || event.input == .toggleInventory {
// Weirdly enough, the vanilla client sends a close window packet when closing the player's
// inventory even though it never tells the server that it opened the inventory in the first
// place. Likely just for the server to verify the slots and chuck out anything in the crafting
// area.
try inventory.window.close(mouseStack: &guiState.mouseItemStack, eventBus: eventBus, connection: connection)
guiState.showInventory = false
}

return true
}


/// - Returns: Whether to suppress the input associated with the event or not.
private func handleWindow(
_ event: KeyPressEvent,
Expand Down
2 changes: 1 addition & 1 deletion Sources/Core/Sources/ECS/Systems/PlayerJumpSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public struct PlayerJumpSystem: System {
)
let block = world.getBlock(at: blockPosition)

let jumpPower = 0.42 * Double(block.material.jumpVelocityMultiplier)
let jumpPower = 0.42 * Double(block.physicalMaterial.jumpVelocityMultiplier)
velocity.y = jumpPower

// Add a bit of extra acceleration if the player is sprinting (this makes sprint jumping faster than sprinting)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public struct PlayerVelocitySystem: System {
x: Int(position.x.rounded(.down)),
y: Int((position.y - 0.5).rounded(.down)),
z: Int(position.z.rounded(.down)))
let material = world.getBlock(at: blockPosition).material
let material = world.getBlock(at: blockPosition).physicalMaterial

velocity.x *= material.velocityMultiplier
velocity.z *= material.velocityMultiplier
Expand Down
13 changes: 9 additions & 4 deletions Sources/Core/Sources/Registry/Block/Block.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ public struct Block: Codable {
public var tint: Tint?
/// A type of random position offset to apply to the block.
public var offset: Offset?
/// The material identifier that vanilla gives to this block.
public var vanillaMaterialIdentifier: Identifier
/// Information about the physical properties of the block.
public var material: PhysicalMaterial
public var physicalMaterial: PhysicalMaterial
/// Information about the way the block interacts with light.
public var lightMaterial: LightMaterial
/// Information about the sound properties of the block.
Expand Down Expand Up @@ -48,7 +50,8 @@ public struct Block: Codable {
fluidState: FluidState? = nil,
tint: Tint? = nil,
offset: Offset? = nil,
material: PhysicalMaterial,
vanillaMaterialIdentifier: Identifier,
physicalMaterial: PhysicalMaterial,
lightMaterial: LightMaterial,
soundMaterial: SoundMaterial,
shape: Shape,
Expand All @@ -61,7 +64,8 @@ public struct Block: Codable {
self.fluidState = fluidState
self.tint = tint
self.offset = offset
self.material = material
self.vanillaMaterialIdentifier = vanillaMaterialIdentifier
self.physicalMaterial = physicalMaterial
self.lightMaterial = lightMaterial
self.soundMaterial = soundMaterial
self.shape = shape
Expand Down Expand Up @@ -104,7 +108,8 @@ public struct Block: Codable {
fluidState: nil,
tint: nil,
offset: nil,
material: PhysicalMaterial.default,
vanillaMaterialIdentifier: Identifier(name: "missing"),
physicalMaterial: PhysicalMaterial.default,
lightMaterial: LightMaterial.default,
soundMaterial: SoundMaterial.default,
shape: Shape.default,
Expand Down
119 changes: 119 additions & 0 deletions Sources/Core/Sources/Registry/Item/Item.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,123 @@ public struct Item: Codable {
public var translationKey: String
/// The id of the block corresponding to this item.
public var blockId: Int?
/// The properties of the item specific to the type of item. `nil` if the item
/// a just a plain old item (e.g. a stick) rather than a tool or an armor piece
/// etc.
public var properties: Properties?

public enum Properties: Codable {
case armor(ArmorProperties)
case tool(ToolProperties)
}

public struct ArmorProperties: Codable {
public var equipmentSlot: EquipmentSlot
public var defense: Int
public var toughness: Double
public var material: Identifier
public var knockbackResistance: Double

public init(
equipmentSlot: Item.ArmorProperties.EquipmentSlot,
defense: Int,
toughness: Double,
material: Identifier,
knockbackResistance: Double
) {
self.equipmentSlot = equipmentSlot
self.defense = defense
self.toughness = toughness
self.material = material
self.knockbackResistance = knockbackResistance
}

public enum EquipmentSlot: String, Codable {
case head
case chest
case legs
case feet
}
}

public struct ToolProperties: Codable {
public var uses: Int
public var level: Int
public var speed: Double
public var attackDamage: Double
public var attackDamageBonus: Double
public var enchantmentValue: Int
/// Blocks that can be mined faster using this tool. Doesn't include
/// blocks covered by ``ToolProperties/effectiveMaterials``.
public var mineableBlocks: [Int]
/// When tools are used to right click blocks, they can cause the block
/// to change state, e.g. a log gets stripped if you right click it with
/// an axe. This mapping doesn't include blocks which are always right
/// clickable.
public var blockInteractions: [Int: Int]
public var kind: ToolKind
/// Materials which this tool is effective on. Used to minimise the length
/// of ``BlockInteractions/mineableBlocks`` by covering large categories of
/// blocks at a time.
public var effectiveMaterials: [Identifier]

public init(
uses: Int,
level: Int,
speed: Double,
attackDamage: Double,
attackDamageBonus: Double,
enchantmentValue: Int,
mineableBlocks: [Int],
blockInteractions: [Int : Int],
kind: Item.ToolProperties.ToolKind,
effectiveMaterials: [Identifier]
) {
self.uses = uses
self.level = level
self.speed = speed
self.attackDamage = attackDamage
self.attackDamageBonus = attackDamageBonus
self.enchantmentValue = enchantmentValue
self.mineableBlocks = mineableBlocks
self.blockInteractions = blockInteractions
self.kind = kind
self.effectiveMaterials = effectiveMaterials
}

public func isEffective(on block: Block) -> Bool {
effectiveMaterials.contains(block.vanillaMaterialIdentifier)
|| mineableBlocks.contains(block.id)
}

public enum ToolKind: String, Codable {
case sword
case pickaxe
case shovel
case hoe
case axe
}
}

public init(
id: Int,
identifier: Identifier,
rarity: ItemRarity,
maximumStackSize: Int,
maximumDamage: Int,
isFireResistant: Bool,
translationKey: String,
blockId: Int? = nil,
properties: Item.Properties? = nil
) {
self.id = id
self.identifier = identifier
self.rarity = rarity
self.maximumStackSize = maximumStackSize
self.maximumDamage = maximumDamage
self.isFireResistant = isFireResistant
self.translationKey = translationKey
self.blockId = blockId
self.properties = properties
}
}
5 changes: 3 additions & 2 deletions Sources/Core/Sources/Registry/Pixlyzer/PixlyzerBlock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ extension Block {
tint = nil
}

let material = Block.PhysicalMaterial(
let physicalMaterial = Block.PhysicalMaterial(
explosionResistance: pixlyzerBlock.explosionResistance,
slipperiness: pixlyzerBlock.friction ?? 0.6,
velocityMultiplier: pixlyzerBlock.velocityMultiplier ?? 1,
Expand Down Expand Up @@ -124,7 +124,8 @@ extension Block {
fluidState: fluidState,
tint: tint,
offset: pixlyzerBlock.offsetType,
material: material,
vanillaMaterialIdentifier: pixlyzerState.material,
physicalMaterial: physicalMaterial,
lightMaterial: lightMaterial,
soundMaterial: soundMaterial,
shape: shape,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ public enum PixlyzerFormatter {
for (identifierString, pixlyzerItem) in pixlyzerItems {
var identifier = try Identifier(identifierString)
identifier.name = "item/\(identifier.name)"
let item = Item(from: pixlyzerItem, identifier: identifier)
let item = try Item(from: pixlyzerItem, identifier: identifier)
items[item.id] = item
}

Expand Down
Loading

0 comments on commit 4a928b4

Please sign in to comment.