mirror of
https://github.com/Jacobwasbeast/LegacyWeaveLoader.git
synced 2026-06-03 03:24:30 +00:00
feat(pickaxe): implement Hooked_PickaxeItemGetDestroySpeed and Hooked_PickaxeItemCanDestroySpecial
- Add hook implementations for custom pickaxe tier support - Hooked_PickaxeItemGetDestroySpeed: use CustomPickaxeRegistry destroy speed for configured pickaxes when mining effective blocks - Hooked_PickaxeItemCanDestroySpecial: use CustomPickaxeRegistry effective blocks and harvest level (obsidian requires level 3) - Add TryReadItemIdFromPickaxe and TryReadTileId helpers for reading item/tile IDs from native pointers
This commit is contained in:
@@ -1,5 +1,20 @@
|
||||
namespace WeaveLoader.API.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Tool type required to harvest a block. Used with <see cref="BlockProperties.RequiredTool"/>.
|
||||
/// </summary>
|
||||
public enum ToolType
|
||||
{
|
||||
/// <summary>No specific tool required; any tool or hand can harvest.</summary>
|
||||
None = 0,
|
||||
/// <summary>Requires a pickaxe.</summary>
|
||||
Pickaxe = 1,
|
||||
/// <summary>Requires an axe.</summary>
|
||||
Axe = 2,
|
||||
/// <summary>Requires a shovel.</summary>
|
||||
Shovel = 3,
|
||||
}
|
||||
|
||||
public enum MaterialType
|
||||
{
|
||||
Air = 0,
|
||||
@@ -48,6 +63,8 @@ public class BlockProperties
|
||||
internal int LightBlockValue = 255;
|
||||
internal CreativeTab CreativeTabValue = CreativeTab.None;
|
||||
internal string? NameValue;
|
||||
internal int RequiredHarvestLevelValue = -1;
|
||||
internal ToolType RequiredToolValue = ToolType.None;
|
||||
|
||||
public BlockProperties Material(MaterialType material) { MaterialValue = material; return this; }
|
||||
public BlockProperties Hardness(float hardness) { HardnessValue = hardness; return this; }
|
||||
@@ -61,4 +78,8 @@ public class BlockProperties
|
||||
public BlockProperties InCreativeTab(CreativeTab tab) { CreativeTabValue = tab; return this; }
|
||||
/// <summary>Display name shown in-game (e.g. "Ruby Ore"). Used for localization.</summary>
|
||||
public BlockProperties Name(string displayName) { NameValue = displayName; return this; }
|
||||
/// <summary>Minimum harvest level required to properly mine this block (e.g. 3 for obsidian). -1 means no requirement.</summary>
|
||||
public BlockProperties RequiredHarvestLevel(int level) { RequiredHarvestLevelValue = level; return this; }
|
||||
/// <summary>Tool type required to harvest this block (e.g. Pickaxe for stone-like blocks).</summary>
|
||||
public BlockProperties RequiredTool(ToolType tool) { RequiredToolValue = tool; return this; }
|
||||
}
|
||||
|
||||
@@ -46,7 +46,9 @@ public static class BlockRegistry
|
||||
properties.IconValue,
|
||||
properties.LightEmissionValue,
|
||||
properties.LightBlockValue,
|
||||
properties.NameValue ?? "");
|
||||
properties.NameValue ?? "",
|
||||
properties.RequiredHarvestLevelValue,
|
||||
(int)properties.RequiredToolValue);
|
||||
|
||||
if (numericId < 0)
|
||||
throw new InvalidOperationException($"Failed to register block '{id}'. No free IDs or invalid parameters.");
|
||||
|
||||
@@ -63,9 +63,31 @@ public enum ToolTier
|
||||
/// Managed pickaxe base class.
|
||||
/// Override callbacks to customize behavior.
|
||||
/// </summary>
|
||||
public class PickaxeItem : Item
|
||||
public abstract class ToolItem : Item
|
||||
{
|
||||
public ToolTier Tier { get; init; } = ToolTier.Diamond;
|
||||
public Identifier? CustomMaterialId { get; init; }
|
||||
}
|
||||
|
||||
public class PickaxeItem : ToolItem
|
||||
{
|
||||
public Identifier? CustomTierId { get; init; }
|
||||
}
|
||||
|
||||
public class ShovelItem : ToolItem
|
||||
{
|
||||
}
|
||||
|
||||
public class HoeItem : ToolItem
|
||||
{
|
||||
}
|
||||
|
||||
public class AxeItem : ToolItem
|
||||
{
|
||||
}
|
||||
|
||||
public class SwordItem : ToolItem
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,6 +7,7 @@ public class ItemProperties
|
||||
{
|
||||
internal int MaxStackSizeValue = 64;
|
||||
internal int MaxDamageValue = 0;
|
||||
internal float AttackDamageValue = 0.0f;
|
||||
internal string IconValue = "";
|
||||
internal CreativeTab CreativeTabValue = CreativeTab.None;
|
||||
internal string? NameValue;
|
||||
@@ -20,6 +21,8 @@ public class ItemProperties
|
||||
/// makes the item damageable with a durability bar.
|
||||
/// </summary>
|
||||
public ItemProperties MaxDamage(int damage) { MaxDamageValue = damage; MaxStackSizeValue = 1; return this; }
|
||||
/// <summary>Override the native attack damage value for tool items.</summary>
|
||||
public ItemProperties AttackDamage(float damage) { AttackDamageValue = damage; return this; }
|
||||
public ItemProperties InCreativeTab(CreativeTab tab) { CreativeTabValue = tab; return this; }
|
||||
/// <summary>Display name shown in-game (e.g. "Ruby"). Used for localization.</summary>
|
||||
public ItemProperties Name(string displayName) { NameValue = displayName; return this; }
|
||||
|
||||
@@ -29,6 +29,56 @@ public static class ItemRegistry
|
||||
private static readonly object s_lock = new();
|
||||
private static readonly Dictionary<int, Identifier> s_idByNumeric = new();
|
||||
|
||||
private enum ToolKind
|
||||
{
|
||||
Pickaxe = 1,
|
||||
Shovel = 2,
|
||||
Hoe = 3,
|
||||
Sword = 4,
|
||||
Axe = 5,
|
||||
}
|
||||
|
||||
private static Identifier? ResolveCustomMaterialId(Item managedItem)
|
||||
{
|
||||
if (managedItem is ToolItem toolItem && toolItem.CustomMaterialId is Identifier customMaterialId)
|
||||
return customMaterialId;
|
||||
|
||||
if (managedItem is PickaxeItem pickaxeItem && pickaxeItem.CustomTierId is Identifier legacyPickaxeTierId)
|
||||
return legacyPickaxeTierId;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static ToolMaterialDefinition? ResolveToolMaterial(Identifier itemId, Item managedItem)
|
||||
{
|
||||
Identifier? customMaterialId = ResolveCustomMaterialId(managedItem);
|
||||
if (customMaterialId == null)
|
||||
return null;
|
||||
|
||||
Identifier resolvedMaterialId = (Identifier)customMaterialId;
|
||||
|
||||
if (!ToolMaterialRegistry.TryGetDefinition(resolvedMaterialId, out ToolMaterialDefinition? definition) || definition == null)
|
||||
throw new InvalidOperationException($"Unknown tool material '{resolvedMaterialId}' for item '{itemId}'.");
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
private static void ConfigureToolMaterial(Identifier itemId, int numericId, ToolKind toolKind, ToolMaterialDefinition? material, ItemProperties properties)
|
||||
{
|
||||
if (material == null && properties.AttackDamageValue <= 0.0f)
|
||||
return;
|
||||
|
||||
int configured = NativeInterop.native_configure_custom_tool_item(
|
||||
numericId,
|
||||
(int)toolKind,
|
||||
material?.HarvestLevelValue ?? 0,
|
||||
material?.DestroySpeedValue ?? 1.0f,
|
||||
properties.AttackDamageValue);
|
||||
|
||||
if (configured == 0)
|
||||
throw new InvalidOperationException($"Failed to configure custom tool material for item '{itemId}'.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a new item with the game engine.
|
||||
/// </summary>
|
||||
@@ -57,12 +107,71 @@ public static class ItemRegistry
|
||||
int numericId;
|
||||
if (managedItem is PickaxeItem pickaxeItem)
|
||||
{
|
||||
ToolMaterialDefinition? material = ResolveToolMaterial(id, pickaxeItem);
|
||||
ToolTier nativeTier = material?.BaseTierValue ?? pickaxeItem.Tier;
|
||||
int maxDamage = properties.MaxDamageValue;
|
||||
|
||||
numericId = NativeInterop.native_register_pickaxe_item(
|
||||
id.ToString(),
|
||||
(int)pickaxeItem.Tier,
|
||||
(int)nativeTier,
|
||||
maxDamage,
|
||||
properties.IconValue,
|
||||
properties.NameValue ?? "");
|
||||
|
||||
if (numericId >= 0)
|
||||
ConfigureToolMaterial(id, numericId, ToolKind.Pickaxe, material, properties);
|
||||
}
|
||||
else if (managedItem is ShovelItem shovelItem)
|
||||
{
|
||||
ToolMaterialDefinition? material = ResolveToolMaterial(id, shovelItem);
|
||||
numericId = NativeInterop.native_register_shovel_item(
|
||||
id.ToString(),
|
||||
(int)(material?.BaseTierValue ?? shovelItem.Tier),
|
||||
properties.MaxDamageValue,
|
||||
properties.IconValue,
|
||||
properties.NameValue ?? "");
|
||||
|
||||
if (numericId >= 0)
|
||||
ConfigureToolMaterial(id, numericId, ToolKind.Shovel, material, properties);
|
||||
}
|
||||
else if (managedItem is HoeItem hoeItem)
|
||||
{
|
||||
ToolMaterialDefinition? material = ResolveToolMaterial(id, hoeItem);
|
||||
numericId = NativeInterop.native_register_hoe_item(
|
||||
id.ToString(),
|
||||
(int)(material?.BaseTierValue ?? hoeItem.Tier),
|
||||
properties.MaxDamageValue,
|
||||
properties.IconValue,
|
||||
properties.NameValue ?? "");
|
||||
|
||||
if (numericId >= 0)
|
||||
ConfigureToolMaterial(id, numericId, ToolKind.Hoe, material, properties);
|
||||
}
|
||||
else if (managedItem is AxeItem axeItem)
|
||||
{
|
||||
ToolMaterialDefinition? material = ResolveToolMaterial(id, axeItem);
|
||||
numericId = NativeInterop.native_register_axe_item(
|
||||
id.ToString(),
|
||||
(int)(material?.BaseTierValue ?? axeItem.Tier),
|
||||
properties.MaxDamageValue,
|
||||
properties.IconValue,
|
||||
properties.NameValue ?? "");
|
||||
|
||||
if (numericId >= 0)
|
||||
ConfigureToolMaterial(id, numericId, ToolKind.Axe, material, properties);
|
||||
}
|
||||
else if (managedItem is SwordItem swordItem)
|
||||
{
|
||||
ToolMaterialDefinition? material = ResolveToolMaterial(id, swordItem);
|
||||
numericId = NativeInterop.native_register_sword_item(
|
||||
id.ToString(),
|
||||
(int)(material?.BaseTierValue ?? swordItem.Tier),
|
||||
properties.MaxDamageValue,
|
||||
properties.IconValue,
|
||||
properties.NameValue ?? "");
|
||||
|
||||
if (numericId >= 0)
|
||||
ConfigureToolMaterial(id, numericId, ToolKind.Sword, material, properties);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
59
WeaveLoader.API/Item/PickaxeTierRegistry.cs
Normal file
59
WeaveLoader.API/Item/PickaxeTierRegistry.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
namespace WeaveLoader.API.Item;
|
||||
|
||||
public sealed class PickaxeTierDefinition
|
||||
{
|
||||
private readonly ToolMaterialDefinition _inner = new();
|
||||
|
||||
internal ToolMaterialDefinition ToToolMaterialDefinition() => _inner;
|
||||
|
||||
public PickaxeTierDefinition BaseTier(ToolTier tier)
|
||||
{
|
||||
_inner.BaseTier(tier);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PickaxeTierDefinition HarvestLevel(int harvestLevel)
|
||||
{
|
||||
if (harvestLevel < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(harvestLevel));
|
||||
|
||||
_inner.HarvestLevel(harvestLevel);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PickaxeTierDefinition DestroySpeed(float destroySpeed)
|
||||
{
|
||||
if (destroySpeed <= 0.0f)
|
||||
throw new ArgumentOutOfRangeException(nameof(destroySpeed));
|
||||
|
||||
_inner.DestroySpeed(destroySpeed);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RegisteredPickaxeTier
|
||||
{
|
||||
public Identifier StringId { get; }
|
||||
|
||||
internal RegisteredPickaxeTier(Identifier stringId)
|
||||
{
|
||||
StringId = stringId;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PickaxeTierRegistry
|
||||
{
|
||||
public static RegisteredPickaxeTier Register(Identifier id, PickaxeTierDefinition definition)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(definition);
|
||||
ToolMaterialRegistry.Register(id, definition.ToToolMaterialDefinition());
|
||||
|
||||
return new RegisteredPickaxeTier(id);
|
||||
}
|
||||
|
||||
internal static bool TryGetDefinition(Identifier id, out PickaxeTierDefinition? definition)
|
||||
{
|
||||
definition = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
72
WeaveLoader.API/Item/ToolMaterialRegistry.cs
Normal file
72
WeaveLoader.API/Item/ToolMaterialRegistry.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
namespace WeaveLoader.API.Item;
|
||||
|
||||
public sealed class ToolMaterialDefinition
|
||||
{
|
||||
public ToolTier BaseTierValue { get; private set; } = ToolTier.Diamond;
|
||||
public int HarvestLevelValue { get; private set; } = 3;
|
||||
public float DestroySpeedValue { get; private set; } = 8.0f;
|
||||
|
||||
public ToolMaterialDefinition BaseTier(ToolTier tier)
|
||||
{
|
||||
BaseTierValue = tier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToolMaterialDefinition HarvestLevel(int harvestLevel)
|
||||
{
|
||||
if (harvestLevel < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(harvestLevel));
|
||||
|
||||
HarvestLevelValue = harvestLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToolMaterialDefinition DestroySpeed(float destroySpeed)
|
||||
{
|
||||
if (destroySpeed <= 0.0f)
|
||||
throw new ArgumentOutOfRangeException(nameof(destroySpeed));
|
||||
|
||||
DestroySpeedValue = destroySpeed;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public sealed class RegisteredToolMaterial
|
||||
{
|
||||
public Identifier StringId { get; }
|
||||
|
||||
internal RegisteredToolMaterial(Identifier stringId)
|
||||
{
|
||||
StringId = stringId;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ToolMaterialRegistry
|
||||
{
|
||||
private static readonly object s_lock = new();
|
||||
private static readonly Dictionary<Identifier, ToolMaterialDefinition> s_materials = new();
|
||||
|
||||
public static RegisteredToolMaterial Register(Identifier id, ToolMaterialDefinition definition)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(definition);
|
||||
|
||||
lock (s_lock)
|
||||
{
|
||||
if (s_materials.ContainsKey(id))
|
||||
throw new InvalidOperationException($"Tool material '{id}' is already registered.");
|
||||
|
||||
s_materials[id] = definition;
|
||||
}
|
||||
|
||||
return new RegisteredToolMaterial(id);
|
||||
}
|
||||
|
||||
internal static bool TryGetDefinition(Identifier id, out ToolMaterialDefinition? definition)
|
||||
{
|
||||
lock (s_lock)
|
||||
{
|
||||
return s_materials.TryGetValue(id, out definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,9 @@ internal static class NativeInterop
|
||||
string iconName,
|
||||
float lightEmission,
|
||||
int lightBlock,
|
||||
string displayName);
|
||||
string displayName,
|
||||
int requiredHarvestLevel,
|
||||
int requiredTool);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_register_item(
|
||||
@@ -38,6 +40,52 @@ internal static class NativeInterop
|
||||
string iconName,
|
||||
string displayName);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_register_shovel_item(
|
||||
string namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
string iconName,
|
||||
string displayName);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_register_hoe_item(
|
||||
string namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
string iconName,
|
||||
string displayName);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_register_axe_item(
|
||||
string namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
string iconName,
|
||||
string displayName);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_register_sword_item(
|
||||
string namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
string iconName,
|
||||
string displayName);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern int native_configure_custom_pickaxe_item(
|
||||
int numericItemId,
|
||||
int harvestLevel,
|
||||
float destroySpeed);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern int native_configure_custom_tool_item(
|
||||
int numericItemId,
|
||||
int toolKind,
|
||||
int harvestLevel,
|
||||
float destroySpeed,
|
||||
float attackDamage);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_allocate_description_id();
|
||||
|
||||
|
||||
@@ -27,6 +27,12 @@ public static class Registry
|
||||
|
||||
public static RegisteredItem Register(Identifier id, WeaveLoader.API.Item.Item item, ItemProperties properties)
|
||||
=> ItemRegistry.Register(id, item, properties);
|
||||
|
||||
public static RegisteredToolMaterial RegisterToolMaterial(Identifier id, ToolMaterialDefinition definition)
|
||||
=> ToolMaterialRegistry.Register(id, definition);
|
||||
|
||||
public static RegisteredPickaxeTier RegisterPickaxeTier(Identifier id, PickaxeTierDefinition definition)
|
||||
=> PickaxeTierRegistry.Register(id, definition);
|
||||
}
|
||||
|
||||
/// <summary>Entity registration. Call Register() with a namespaced ID and EntityDefinition.</summary>
|
||||
|
||||
Reference in New Issue
Block a user