mirror of
https://github.com/Jacobwasbeast/LegacyWeaveLoader.git
synced 2026-06-15 09:22:46 +00:00
Initial commit: LegacyForge mod loader for Minecraft Legacy Edition
SKSE-style external mod loader with zero game source modifications. - LegacyForge.Launcher: C# console app that injects runtime DLL into game process - LegacyForgeRuntime: C++ DLL with PDB symbol resolution, MinHook function hooking, and .NET CoreCLR hosting - LegacyForge.Core: C# mod discovery and lifecycle management - LegacyForge.API: Fabric-style mod API with namespaced string IDs, fluent property builders, and event system - ExampleMod: Sample mod demonstrating block/item registration
This commit is contained in:
58
LegacyForge.API/Block/BlockProperties.cs
Normal file
58
LegacyForge.API/Block/BlockProperties.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
namespace LegacyForge.API.Block;
|
||||
|
||||
public enum MaterialType
|
||||
{
|
||||
Air = 0,
|
||||
Stone = 1,
|
||||
Wood = 2,
|
||||
Cloth = 3,
|
||||
Plant = 4,
|
||||
Dirt = 5,
|
||||
Sand = 6,
|
||||
Glass = 7,
|
||||
Water = 8,
|
||||
Lava = 9,
|
||||
Ice = 10,
|
||||
Metal = 11,
|
||||
Snow = 12,
|
||||
Clay = 13,
|
||||
Explosive = 14,
|
||||
Web = 15
|
||||
}
|
||||
|
||||
public enum SoundType
|
||||
{
|
||||
None = 0,
|
||||
Stone = 1,
|
||||
Wood = 2,
|
||||
Gravel = 3,
|
||||
Grass = 4,
|
||||
Metal = 5,
|
||||
Glass = 6,
|
||||
Cloth = 7,
|
||||
Sand = 8,
|
||||
Snow = 9
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluent builder for defining block properties.
|
||||
/// </summary>
|
||||
public class BlockProperties
|
||||
{
|
||||
internal MaterialType MaterialValue = MaterialType.Stone;
|
||||
internal float HardnessValue = 1.0f;
|
||||
internal float ResistanceValue = 5.0f;
|
||||
internal SoundType SoundValue = SoundType.Stone;
|
||||
internal string IconValue = "stone";
|
||||
internal float LightEmissionValue = 0.0f;
|
||||
internal int LightBlockValue = 255;
|
||||
|
||||
public BlockProperties Material(MaterialType material) { MaterialValue = material; return this; }
|
||||
public BlockProperties Hardness(float hardness) { HardnessValue = hardness; return this; }
|
||||
public BlockProperties Resistance(float resistance) { ResistanceValue = resistance; return this; }
|
||||
public BlockProperties Sound(SoundType sound) { SoundValue = sound; return this; }
|
||||
public BlockProperties Icon(string iconName) { IconValue = iconName; return this; }
|
||||
public BlockProperties LightLevel(float level) { LightEmissionValue = level; return this; }
|
||||
public BlockProperties LightBlocking(int level) { LightBlockValue = level; return this; }
|
||||
public BlockProperties Indestructible() { HardnessValue = -1.0f; ResistanceValue = 6000000f; return this; }
|
||||
}
|
||||
51
LegacyForge.API/Block/BlockRegistry.cs
Normal file
51
LegacyForge.API/Block/BlockRegistry.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
namespace LegacyForge.API.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a block that has been registered with the game engine.
|
||||
/// </summary>
|
||||
public class RegisteredBlock
|
||||
{
|
||||
/// <summary>The namespaced string ID (e.g. "mymod:ruby_ore").</summary>
|
||||
public Identifier StringId { get; }
|
||||
|
||||
/// <summary>The numeric ID allocated by the engine.</summary>
|
||||
public int NumericId { get; }
|
||||
|
||||
internal RegisteredBlock(Identifier id, int numericId)
|
||||
{
|
||||
StringId = id;
|
||||
NumericId = numericId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Block registration via the LegacyForge registry.
|
||||
/// Accessed through <see cref="Registry.Block"/>.
|
||||
/// </summary>
|
||||
public static class BlockRegistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Register a new block with the game engine.
|
||||
/// </summary>
|
||||
/// <param name="id">Namespaced identifier (e.g. "mymod:ruby_ore").</param>
|
||||
/// <param name="properties">Block properties built with <see cref="BlockProperties"/>.</param>
|
||||
/// <returns>A handle to the registered block.</returns>
|
||||
public static RegisteredBlock Register(Identifier id, BlockProperties properties)
|
||||
{
|
||||
int numericId = NativeInterop.native_register_block(
|
||||
id.ToString(),
|
||||
(int)properties.MaterialValue,
|
||||
properties.HardnessValue,
|
||||
properties.ResistanceValue,
|
||||
(int)properties.SoundValue,
|
||||
properties.IconValue,
|
||||
properties.LightEmissionValue,
|
||||
properties.LightBlockValue);
|
||||
|
||||
if (numericId < 0)
|
||||
throw new InvalidOperationException($"Failed to register block '{id}'. No free IDs or invalid parameters.");
|
||||
|
||||
Logger.Debug($"Registered block '{id}' -> numeric ID {numericId}");
|
||||
return new RegisteredBlock(id, numericId);
|
||||
}
|
||||
}
|
||||
16
LegacyForge.API/Entity/EntityDefinition.cs
Normal file
16
LegacyForge.API/Entity/EntityDefinition.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace LegacyForge.API.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Fluent builder for defining entity properties.
|
||||
/// </summary>
|
||||
public class EntityDefinition
|
||||
{
|
||||
internal float WidthValue = 0.6f;
|
||||
internal float HeightValue = 1.8f;
|
||||
internal int TrackingRangeValue = 80;
|
||||
|
||||
public EntityDefinition Width(float width) { WidthValue = width; return this; }
|
||||
public EntityDefinition Height(float height) { HeightValue = height; return this; }
|
||||
public EntityDefinition TrackingRange(int range) { TrackingRangeValue = range; return this; }
|
||||
public EntityDefinition Size(float width, float height) { WidthValue = width; HeightValue = height; return this; }
|
||||
}
|
||||
38
LegacyForge.API/Entity/EntityRegistry.cs
Normal file
38
LegacyForge.API/Entity/EntityRegistry.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace LegacyForge.API.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an entity type that has been registered with the game engine.
|
||||
/// </summary>
|
||||
public class RegisteredEntity
|
||||
{
|
||||
public Identifier StringId { get; }
|
||||
public int NumericId { get; }
|
||||
|
||||
internal RegisteredEntity(Identifier id, int numericId)
|
||||
{
|
||||
StringId = id;
|
||||
NumericId = numericId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entity registration via the LegacyForge registry.
|
||||
/// Accessed through <see cref="Registry.Entity"/>.
|
||||
/// </summary>
|
||||
public static class EntityRegistry
|
||||
{
|
||||
public static RegisteredEntity Register(Identifier id, EntityDefinition definition)
|
||||
{
|
||||
int numericId = NativeInterop.native_register_entity(
|
||||
id.ToString(),
|
||||
definition.WidthValue,
|
||||
definition.HeightValue,
|
||||
definition.TrackingRangeValue);
|
||||
|
||||
if (numericId < 0)
|
||||
throw new InvalidOperationException($"Failed to register entity '{id}'.");
|
||||
|
||||
Logger.Debug($"Registered entity '{id}' -> numeric ID {numericId}");
|
||||
return new RegisteredEntity(id, numericId);
|
||||
}
|
||||
}
|
||||
60
LegacyForge.API/Events/GameEvents.cs
Normal file
60
LegacyForge.API/Events/GameEvents.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace LegacyForge.API.Events;
|
||||
|
||||
public class TickEventArgs : EventArgs { }
|
||||
|
||||
public class BlockBreakEventArgs : EventArgs
|
||||
{
|
||||
public string BlockId { get; init; } = "";
|
||||
public int X { get; init; }
|
||||
public int Y { get; init; }
|
||||
public int Z { get; init; }
|
||||
public int PlayerId { get; init; }
|
||||
}
|
||||
|
||||
public class BlockPlaceEventArgs : EventArgs
|
||||
{
|
||||
public string BlockId { get; init; } = "";
|
||||
public int X { get; init; }
|
||||
public int Y { get; init; }
|
||||
public int Z { get; init; }
|
||||
public int PlayerId { get; init; }
|
||||
}
|
||||
|
||||
public class ChatEventArgs : EventArgs
|
||||
{
|
||||
public string Message { get; init; } = "";
|
||||
public int PlayerId { get; init; }
|
||||
}
|
||||
|
||||
public class EntitySpawnEventArgs : EventArgs
|
||||
{
|
||||
public string EntityId { get; init; } = "";
|
||||
public float X { get; init; }
|
||||
public float Y { get; init; }
|
||||
public float Z { get; init; }
|
||||
}
|
||||
|
||||
public class PlayerJoinEventArgs : EventArgs
|
||||
{
|
||||
public int PlayerId { get; init; }
|
||||
public string PlayerName { get; init; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Global game event subscriptions. Subscribe to these in your mod's OnInitialize().
|
||||
/// Events are fired from the game's main thread via hooks in LegacyForgeRuntime.
|
||||
/// </summary>
|
||||
public static class GameEvents
|
||||
{
|
||||
public static event EventHandler<BlockBreakEventArgs>? OnBlockBreak;
|
||||
public static event EventHandler<BlockPlaceEventArgs>? OnBlockPlace;
|
||||
public static event EventHandler<ChatEventArgs>? OnChat;
|
||||
public static event EventHandler<EntitySpawnEventArgs>? OnEntitySpawn;
|
||||
public static event EventHandler<PlayerJoinEventArgs>? OnPlayerJoin;
|
||||
|
||||
internal static void FireBlockBreak(BlockBreakEventArgs e) => OnBlockBreak?.Invoke(null, e);
|
||||
internal static void FireBlockPlace(BlockPlaceEventArgs e) => OnBlockPlace?.Invoke(null, e);
|
||||
internal static void FireChat(ChatEventArgs e) => OnChat?.Invoke(null, e);
|
||||
internal static void FireEntitySpawn(EntitySpawnEventArgs e) => OnEntitySpawn?.Invoke(null, e);
|
||||
internal static void FirePlayerJoin(PlayerJoinEventArgs e) => OnPlayerJoin?.Invoke(null, e);
|
||||
}
|
||||
39
LegacyForge.API/IMod.cs
Normal file
39
LegacyForge.API/IMod.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
namespace LegacyForge.API;
|
||||
|
||||
/// <summary>
|
||||
/// The main interface all LegacyForge mods must implement.
|
||||
/// Default interface methods allow mods to only override what they need.
|
||||
/// </summary>
|
||||
public interface IMod
|
||||
{
|
||||
/// <summary>
|
||||
/// Called before vanilla registries are populated.
|
||||
/// Use for very early setup that must happen before any game content loads.
|
||||
/// </summary>
|
||||
void OnPreInit() { }
|
||||
|
||||
/// <summary>
|
||||
/// Called after vanilla registries are populated.
|
||||
/// This is the main initialization point -- register your blocks, items,
|
||||
/// entities, recipes, and event handlers here.
|
||||
/// </summary>
|
||||
void OnInitialize();
|
||||
|
||||
/// <summary>
|
||||
/// Called after the game client has finished its own initialization.
|
||||
/// Use for client-side setup like custom renderers or UI.
|
||||
/// </summary>
|
||||
void OnPostInitialize() { }
|
||||
|
||||
/// <summary>
|
||||
/// Called once per game tick (20 times per second).
|
||||
/// Use for ongoing mod logic.
|
||||
/// </summary>
|
||||
void OnTick() { }
|
||||
|
||||
/// <summary>
|
||||
/// Called when the game is shutting down.
|
||||
/// Use for cleanup and saving mod state.
|
||||
/// </summary>
|
||||
void OnShutdown() { }
|
||||
}
|
||||
39
LegacyForge.API/Identifier.cs
Normal file
39
LegacyForge.API/Identifier.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
namespace LegacyForge.API;
|
||||
|
||||
/// <summary>
|
||||
/// A namespaced identifier in the form "namespace:path" (e.g. "minecraft:stone", "mymod:ruby_ore").
|
||||
/// </summary>
|
||||
public readonly record struct Identifier
|
||||
{
|
||||
public string Namespace { get; }
|
||||
public string Path { get; }
|
||||
|
||||
public Identifier(string ns, string path)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(ns);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(path);
|
||||
Namespace = ns;
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public Identifier(string id)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(id);
|
||||
|
||||
var colonIndex = id.IndexOf(':');
|
||||
if (colonIndex < 0)
|
||||
{
|
||||
Namespace = "minecraft";
|
||||
Path = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
Namespace = id[..colonIndex];
|
||||
Path = id[(colonIndex + 1)..];
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => $"{Namespace}:{Path}";
|
||||
|
||||
public static implicit operator Identifier(string id) => new(id);
|
||||
}
|
||||
18
LegacyForge.API/Item/ItemProperties.cs
Normal file
18
LegacyForge.API/Item/ItemProperties.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace LegacyForge.API.Item;
|
||||
|
||||
/// <summary>
|
||||
/// Fluent builder for defining item properties.
|
||||
/// </summary>
|
||||
public class ItemProperties
|
||||
{
|
||||
internal int MaxStackSizeValue = 64;
|
||||
internal int MaxDamageValue = 0;
|
||||
|
||||
public ItemProperties MaxStackSize(int size) { MaxStackSizeValue = size; return this; }
|
||||
|
||||
/// <summary>
|
||||
/// Set max damage for a tool/armor item. Setting this to a positive value
|
||||
/// makes the item damageable with a durability bar.
|
||||
/// </summary>
|
||||
public ItemProperties MaxDamage(int damage) { MaxDamageValue = damage; MaxStackSizeValue = 1; return this; }
|
||||
}
|
||||
46
LegacyForge.API/Item/ItemRegistry.cs
Normal file
46
LegacyForge.API/Item/ItemRegistry.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
namespace LegacyForge.API.Item;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an item that has been registered with the game engine.
|
||||
/// </summary>
|
||||
public class RegisteredItem
|
||||
{
|
||||
/// <summary>The namespaced string ID (e.g. "mymod:ruby").</summary>
|
||||
public Identifier StringId { get; }
|
||||
|
||||
/// <summary>The numeric ID allocated by the engine.</summary>
|
||||
public int NumericId { get; }
|
||||
|
||||
internal RegisteredItem(Identifier id, int numericId)
|
||||
{
|
||||
StringId = id;
|
||||
NumericId = numericId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Item registration via the LegacyForge registry.
|
||||
/// Accessed through <see cref="Registry.Item"/>.
|
||||
/// </summary>
|
||||
public static class ItemRegistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Register a new item with the game engine.
|
||||
/// </summary>
|
||||
/// <param name="id">Namespaced identifier (e.g. "mymod:ruby").</param>
|
||||
/// <param name="properties">Item properties built with <see cref="ItemProperties"/>.</param>
|
||||
/// <returns>A handle to the registered item.</returns>
|
||||
public static RegisteredItem Register(Identifier id, ItemProperties properties)
|
||||
{
|
||||
int numericId = NativeInterop.native_register_item(
|
||||
id.ToString(),
|
||||
properties.MaxStackSizeValue,
|
||||
properties.MaxDamageValue);
|
||||
|
||||
if (numericId < 0)
|
||||
throw new InvalidOperationException($"Failed to register item '{id}'. No free IDs or invalid parameters.");
|
||||
|
||||
Logger.Debug($"Registered item '{id}' -> numeric ID {numericId}");
|
||||
return new RegisteredItem(id, numericId);
|
||||
}
|
||||
}
|
||||
13
LegacyForge.API/LegacyForge.API.csproj
Normal file
13
LegacyForge.API/LegacyForge.API.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>LegacyForge.API</RootNamespace>
|
||||
<AssemblyName>LegacyForge.API</AssemblyName>
|
||||
<Description>Mod API for LegacyForge - Minecraft Legacy Edition mod loader</Description>
|
||||
<Version>1.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
30
LegacyForge.API/Logger.cs
Normal file
30
LegacyForge.API/Logger.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace LegacyForge.API;
|
||||
|
||||
public enum LogLevel
|
||||
{
|
||||
Debug = 0,
|
||||
Info = 1,
|
||||
Warning = 2,
|
||||
Error = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logging facade that routes messages through the native runtime to the game's debug output.
|
||||
/// </summary>
|
||||
public static class Logger
|
||||
{
|
||||
internal static Action<string, LogLevel>? LogHandler;
|
||||
|
||||
public static void Debug(string message) => Log(message, LogLevel.Debug);
|
||||
public static void Info(string message) => Log(message, LogLevel.Info);
|
||||
public static void Warning(string message) => Log(message, LogLevel.Warning);
|
||||
public static void Error(string message) => Log(message, LogLevel.Error);
|
||||
|
||||
public static void Log(string message, LogLevel level = LogLevel.Info)
|
||||
{
|
||||
if (LogHandler != null)
|
||||
LogHandler(message, level);
|
||||
else
|
||||
Console.WriteLine($"[LegacyForge/{level}] {message}");
|
||||
}
|
||||
}
|
||||
41
LegacyForge.API/ModAttribute.cs
Normal file
41
LegacyForge.API/ModAttribute.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace LegacyForge.API;
|
||||
|
||||
/// <summary>
|
||||
/// Marks a class as a LegacyForge mod and provides metadata.
|
||||
/// The class must also implement <see cref="IMod"/>.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class ModAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique mod identifier (e.g. "examplemod"). Used as the default namespace
|
||||
/// for content registered by this mod.
|
||||
/// </summary>
|
||||
public string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable display name.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Semantic version string (e.g. "1.0.0").
|
||||
/// </summary>
|
||||
public string Version { get; set; } = "1.0.0";
|
||||
|
||||
/// <summary>
|
||||
/// Mod author(s).
|
||||
/// </summary>
|
||||
public string Author { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Short description of the mod.
|
||||
/// </summary>
|
||||
public string Description { get; set; } = "";
|
||||
|
||||
public ModAttribute(string id)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(id);
|
||||
Id = id;
|
||||
}
|
||||
}
|
||||
64
LegacyForge.API/NativeInterop.cs
Normal file
64
LegacyForge.API/NativeInterop.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LegacyForge.API;
|
||||
|
||||
/// <summary>
|
||||
/// Internal P/Invoke bindings to LegacyForgeRuntime.dll native exports.
|
||||
/// Mod authors should use the Registry and Logger classes instead of calling these directly.
|
||||
/// </summary>
|
||||
internal static class NativeInterop
|
||||
{
|
||||
private const string RuntimeDll = "LegacyForgeRuntime";
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_register_block(
|
||||
string namespacedId,
|
||||
int materialId,
|
||||
float hardness,
|
||||
float resistance,
|
||||
int soundType,
|
||||
string iconName,
|
||||
float lightEmission,
|
||||
int lightBlock);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_register_item(
|
||||
string namespacedId,
|
||||
int maxStackSize,
|
||||
int maxDamage);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_register_entity(
|
||||
string namespacedId,
|
||||
float width,
|
||||
float height,
|
||||
int trackingRange);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern void native_add_shaped_recipe(
|
||||
string resultId,
|
||||
int resultCount,
|
||||
string pattern,
|
||||
string ingredientIds);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern void native_add_furnace_recipe(
|
||||
string inputId,
|
||||
string outputId,
|
||||
float xp);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern void native_log(string message, int level);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_get_block_id(string namespacedId);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_get_item_id(string namespacedId);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern int native_get_entity_id(string namespacedId);
|
||||
|
||||
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
internal static extern void native_subscribe_event(string eventName, IntPtr managedFnPtr);
|
||||
}
|
||||
40
LegacyForge.API/Recipe/RecipeRegistry.cs
Normal file
40
LegacyForge.API/Recipe/RecipeRegistry.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
namespace LegacyForge.API.Recipe;
|
||||
|
||||
/// <summary>
|
||||
/// Recipe registration via the LegacyForge registry.
|
||||
/// Accessed through <see cref="Registry.Recipe"/>.
|
||||
/// </summary>
|
||||
public static class RecipeRegistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Add a shaped crafting recipe.
|
||||
/// </summary>
|
||||
/// <param name="result">The output item identifier.</param>
|
||||
/// <param name="resultCount">Number of items produced.</param>
|
||||
/// <param name="pattern">Crafting grid pattern rows (e.g. "XXX", " | ", " | " for a pickaxe).</param>
|
||||
/// <param name="keys">Character-to-ingredient mappings.</param>
|
||||
public static void AddShaped(Identifier result, int resultCount, string[] pattern,
|
||||
params (char key, Identifier ingredient)[] keys)
|
||||
{
|
||||
string patternStr = string.Join(";", pattern);
|
||||
string ingredientStr = string.Join(";",
|
||||
keys.Select(k => $"{k.key}={k.ingredient}"));
|
||||
|
||||
NativeInterop.native_add_shaped_recipe(
|
||||
result.ToString(), resultCount, patternStr, ingredientStr);
|
||||
|
||||
Logger.Debug($"Added shaped recipe -> {resultCount}x {result}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a furnace/smelting recipe.
|
||||
/// </summary>
|
||||
/// <param name="input">The input item/block identifier.</param>
|
||||
/// <param name="output">The output item identifier.</param>
|
||||
/// <param name="xp">Experience granted per smelt.</param>
|
||||
public static void AddFurnace(Identifier input, Identifier output, float xp)
|
||||
{
|
||||
NativeInterop.native_add_furnace_recipe(input.ToString(), output.ToString(), xp);
|
||||
Logger.Debug($"Added furnace recipe: {input} -> {output} ({xp} xp)");
|
||||
}
|
||||
}
|
||||
45
LegacyForge.API/Registry.cs
Normal file
45
LegacyForge.API/Registry.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using LegacyForge.API.Block;
|
||||
using LegacyForge.API.Item;
|
||||
using LegacyForge.API.Entity;
|
||||
using LegacyForge.API.Recipe;
|
||||
|
||||
namespace LegacyForge.API;
|
||||
|
||||
/// <summary>
|
||||
/// Central access point for all LegacyForge registries.
|
||||
/// Use Registry.Block, Registry.Item, Registry.Entity, or Registry.Recipe to register content.
|
||||
/// </summary>
|
||||
public static class Registry
|
||||
{
|
||||
/// <summary>Block registration. Call Register() with a namespaced ID and BlockProperties.</summary>
|
||||
public static class Block
|
||||
{
|
||||
public static RegisteredBlock Register(Identifier id, BlockProperties properties)
|
||||
=> BlockRegistry.Register(id, properties);
|
||||
}
|
||||
|
||||
/// <summary>Item registration. Call Register() with a namespaced ID and ItemProperties.</summary>
|
||||
public static class Item
|
||||
{
|
||||
public static RegisteredItem Register(Identifier id, ItemProperties properties)
|
||||
=> ItemRegistry.Register(id, properties);
|
||||
}
|
||||
|
||||
/// <summary>Entity registration. Call Register() with a namespaced ID and EntityDefinition.</summary>
|
||||
public static class Entity
|
||||
{
|
||||
public static RegisteredEntity Register(Identifier id, EntityDefinition definition)
|
||||
=> EntityRegistry.Register(id, definition);
|
||||
}
|
||||
|
||||
/// <summary>Recipe registration for crafting and smelting.</summary>
|
||||
public static class Recipe
|
||||
{
|
||||
public static void AddShaped(Identifier result, int count, string[] pattern,
|
||||
params (char key, Identifier ingredient)[] keys)
|
||||
=> RecipeRegistry.AddShaped(result, count, pattern, keys);
|
||||
|
||||
public static void AddFurnace(Identifier input, Identifier output, float xp)
|
||||
=> RecipeRegistry.AddFurnace(input, output, xp);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user