新增原生工具调用数据结构与解析:SimpleAIClient.cs
AITool 增加 Schema 构造器与函数定义生成,所有工具补齐 GetParametersSchema():AITool.cs 与 *.cs
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Verse;
|
||||
@@ -13,10 +14,27 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public abstract string Name { get; }
|
||||
public abstract string Description { get; }
|
||||
public abstract string UsageSchema { get; } // JSON schema description
|
||||
public abstract Dictionary<string, object> GetParametersSchema();
|
||||
|
||||
public virtual string Execute(string args) => "Error: Synchronous execution not supported for this tool.";
|
||||
public virtual Task<string> ExecuteAsync(string args) => Task.FromResult(Execute(args));
|
||||
|
||||
public virtual Dictionary<string, object> GetFunctionDefinition()
|
||||
{
|
||||
var parameters = GetParametersSchema() ?? SchemaObject(new Dictionary<string, object>(), new string[] { });
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
["type"] = "function",
|
||||
["function"] = new Dictionary<string, object>
|
||||
{
|
||||
["name"] = Name ?? "",
|
||||
["description"] = Description ?? "",
|
||||
["parameters"] = parameters,
|
||||
["strict"] = true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to parse JSON arguments into a dictionary.
|
||||
/// </summary>
|
||||
@@ -116,6 +134,64 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
return JsonToolCallParser.LooksLikeJson(input);
|
||||
}
|
||||
|
||||
protected static Dictionary<string, object> SchemaString(string description = null, bool nullable = false)
|
||||
{
|
||||
return SchemaPrimitive("string", description, nullable);
|
||||
}
|
||||
|
||||
protected static Dictionary<string, object> SchemaInteger(string description = null, bool nullable = false)
|
||||
{
|
||||
return SchemaPrimitive("integer", description, nullable);
|
||||
}
|
||||
|
||||
protected static Dictionary<string, object> SchemaNumber(string description = null, bool nullable = false)
|
||||
{
|
||||
return SchemaPrimitive("number", description, nullable);
|
||||
}
|
||||
|
||||
protected static Dictionary<string, object> SchemaBoolean(string description = null, bool nullable = false)
|
||||
{
|
||||
return SchemaPrimitive("boolean", description, nullable);
|
||||
}
|
||||
|
||||
protected static Dictionary<string, object> SchemaArray(object itemSchema, string description = null, bool nullable = false)
|
||||
{
|
||||
var schema = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = nullable ? new List<object> { "array", "null" } : "array",
|
||||
["items"] = itemSchema
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(description))
|
||||
{
|
||||
schema["description"] = description;
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
protected static Dictionary<string, object> SchemaObject(Dictionary<string, object> properties, IEnumerable<string> required, string description = null, bool nullable = false)
|
||||
{
|
||||
var schema = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = nullable ? new List<object> { "object", "null" } : "object",
|
||||
["properties"] = properties ?? new Dictionary<string, object>(),
|
||||
["additionalProperties"] = false
|
||||
};
|
||||
if (required != null)
|
||||
{
|
||||
schema["required"] = required.Select(r => (object)r).ToList();
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(description))
|
||||
{
|
||||
schema["description"] = description;
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
protected static List<string> RequiredList(params string[] fields)
|
||||
{
|
||||
return fields?.Where(f => !string.IsNullOrWhiteSpace(f)).ToList() ?? new List<string>();
|
||||
}
|
||||
|
||||
private static bool TryGetNumber(Dictionary<string, object> args, string key, out double value)
|
||||
{
|
||||
value = 0;
|
||||
@@ -148,5 +224,18 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> SchemaPrimitive(string type, string description, bool nullable)
|
||||
{
|
||||
var schema = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = nullable ? new List<object> { type, "null" } : type
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(description))
|
||||
{
|
||||
schema["description"] = description;
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,15 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
"Analyze the current game screen screenshot. Provide an instruction to guide the analysis.";
|
||||
|
||||
public override string UsageSchema => "{\"instruction\":\"Describe the current screen\"}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["instruction"] = SchemaString("Instruction for image analysis.", nullable: true),
|
||||
["context"] = SchemaString("Alias for instruction.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("instruction", "context"));
|
||||
}
|
||||
|
||||
private const string BaseVisionSystemPrompt = "You are a seasoned RimWorld assistant. Analyze the screenshot per instruction. Keep replies concise. Do not output tool call JSON unless explicitly asked.";
|
||||
|
||||
|
||||
@@ -14,6 +14,31 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "call_bombardment";
|
||||
public override string Description => "Calls orbital bombardment/support using an AbilityDef configuration (e.g., WULA_Firepower_Cannon_Salvo, WULA_Firepower_EnergyLance_Strafe). Supports Circular Bombardment, Strafe, Energy Lance, and Surveillance.";
|
||||
public override string UsageSchema => "{\"abilityDef\":\"WULA_Firepower_Cannon_Salvo\",\"x\":12,\"z\":34,\"direction\":\"20,30\",\"angle\":90,\"filterFriendlyFire\":true}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["abilityDef"] = SchemaString("AbilityDef defName.", nullable: true),
|
||||
["x"] = SchemaInteger("Target cell X.", nullable: true),
|
||||
["z"] = SchemaInteger("Target cell Z.", nullable: true),
|
||||
["cell"] = SchemaString("Target cell formatted as 'x,z'.", nullable: true),
|
||||
["direction"] = SchemaString("Direction cell 'x,z' for strafes.", nullable: true),
|
||||
["angle"] = SchemaNumber("Angle for strafe/lance direction.", nullable: true),
|
||||
["filterFriendlyFire"] = SchemaBoolean("Avoid friendly fire if possible.", nullable: true),
|
||||
["dirX"] = SchemaInteger("Direction cell X.", nullable: true),
|
||||
["dirZ"] = SchemaInteger("Direction cell Z.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList(
|
||||
"abilityDef",
|
||||
"x",
|
||||
"z",
|
||||
"cell",
|
||||
"direction",
|
||||
"angle",
|
||||
"filterFriendlyFire",
|
||||
"dirX",
|
||||
"dirZ"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,17 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
"TIP: Use the 'get_available_prefabs' tool first to see which structures are available. " +
|
||||
"The default skyfaller animation is 'WULA_Prefab_Incoming'.";
|
||||
public override string UsageSchema => "{\"prefabDefName\":\"WULA_NewColonyBase\",\"skyfallerDef\":\"WULA_Prefab_Incoming\",\"x\":10,\"z\":20}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["prefabDefName"] = SchemaString("PrefabDef defName.", nullable: true),
|
||||
["skyfallerDef"] = SchemaString("Skyfaller ThingDef defName.", nullable: true),
|
||||
["x"] = SchemaInteger("Target cell X.", nullable: true),
|
||||
["z"] = SchemaInteger("Target cell Z.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("prefabDefName", "skyfallerDef", "x", "z"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using WulaFallenEmpire.EventSystem.AI;
|
||||
|
||||
@@ -9,6 +10,14 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "change_expression";
|
||||
public override string Description => "Changes your visual expression/portrait to match your current mood or reaction.";
|
||||
public override string UsageSchema => "{\"expression_id\": 2}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["expression_id"] = SchemaInteger("Expression id (1-6).", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("expression_id"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,10 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Description => "Returns a list of available orbital bombardment abilities (AbilityDefs) that can be called. " +
|
||||
"Use this to find the correct 'abilityDef' for the 'call_bombardment' tool.";
|
||||
public override string UsageSchema => "{}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
return SchemaObject(new Dictionary<string, object>(), RequiredList());
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,10 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Description => "Returns a list of available building prefabs (blueprints) that can be summoned. " +
|
||||
"Use this to find the correct 'prefabDefName' for the 'call_prefab_airdrop' tool.";
|
||||
public override string UsageSchema => "{}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
return SchemaObject(new Dictionary<string, object>(), RequiredList());
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,16 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Description => "Scans the current map and lists pawns (including corpses). Supports filtering by relation (friendly/hostile/neutral), type (colonist/animal/mech/humanlike), and status (prisoner/slave/guest/wild/downed/dead).";
|
||||
public override string UsageSchema =>
|
||||
"{\"filter\":\"friendly,hostile,colonist\",\"includeDead\":true,\"maxResults\":50}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["filter"] = SchemaString("Comma-separated filters (friendly, hostile, colonist, etc.).", nullable: true),
|
||||
["includeDead"] = SchemaBoolean("Include corpses.", nullable: true),
|
||||
["maxResults"] = SchemaInteger("Max results to show.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("filter", "includeDead", "maxResults"));
|
||||
}
|
||||
|
||||
private struct MapPawnEntry
|
||||
{
|
||||
|
||||
@@ -13,6 +13,14 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "get_map_resources";
|
||||
public override string Description => "Checks the player's map for specific resources or buildings. Use this to verify if the player is truly lacking something they requested (e.g., 'we need steel'). Returns inventory count and mineable deposits.";
|
||||
public override string UsageSchema => "{\"resourceName\":\"Steel\"}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["resourceName"] = SchemaString("Thing label or defName to check.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("resourceName"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,16 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "get_pawn_status";
|
||||
public override string Description => "Returns detailed status (health, needs, gear) of specified pawns. Use this to check for sickness, injuries, mood, or equipment. Can filter by name, category (colonist/animal/prisoner/guest), or status (sick/injured).";
|
||||
public override string UsageSchema => "{\"name\":\"optional\",\"category\":\"colonist\",\"filter\":\"sick\"}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["name"] = SchemaString("Name filter (substring).", nullable: true),
|
||||
["category"] = SchemaString("colonist/animal/prisoner/guest/all.", nullable: true),
|
||||
["filter"] = SchemaString("sick/injured/downed/dead.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("name", "category", "filter"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,16 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Description => "Returns the most recent letters and messages, sorted by in-game time from newest to oldest.";
|
||||
public override string UsageSchema =>
|
||||
"{\"count\":10,\"includeLetters\":true,\"includeMessages\":true}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["count"] = SchemaInteger("Max notifications to return.", nullable: true),
|
||||
["includeLetters"] = SchemaBoolean("Include letters.", nullable: true),
|
||||
["includeMessages"] = SchemaBoolean("Include messages.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("count", "includeLetters", "includeMessages"));
|
||||
}
|
||||
|
||||
private struct NotificationEntry
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
@@ -9,6 +10,14 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "modify_goodwill";
|
||||
public override string Description => "Adjusts YOUR internal opinion of the player (AI Goodwill). WARNING: This DOES NOT affect Faction Relations or stop raids. It is purely personal. Do NOT use this to try to stop enemies.";
|
||||
public override string UsageSchema => "{\"amount\": 1}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["amount"] = SchemaInteger("Change in goodwill (-5 to 5).", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("amount"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,15 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "recall_memories";
|
||||
public override string Description => "Searches the AI's long-term memory for facts matching a specific query or keyword.";
|
||||
public override string UsageSchema => "{\"query\":\"keywords\",\"limit\":5}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["query"] = SchemaString("Search query.", nullable: true),
|
||||
["limit"] = SchemaInteger("Max memories to return.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("query", "limit"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,15 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "remember_fact";
|
||||
public override string Description => "Stores a specific fact or piece of information into the AI's long-term memory for future retrieval.";
|
||||
public override string UsageSchema => "{\"fact\":\"...\",\"category\":\"misc\"}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["fact"] = SchemaString("Fact to store.", nullable: true),
|
||||
["category"] = SchemaString("Memory category.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("fact", "category"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
@@ -11,6 +12,16 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "search_pawn_kind";
|
||||
public override string Description => "Rough-searches PawnKindDefs by natural language (label/defName). Returns candidate defNames for send_reinforcement.";
|
||||
public override string UsageSchema => "{\"query\":\"escort\",\"maxResults\":10,\"minScore\":0.15}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["query"] = SchemaString("Search query.", nullable: true),
|
||||
["maxResults"] = SchemaInteger("Max candidates to return.", nullable: true),
|
||||
["minScore"] = SchemaNumber("Minimum similarity score.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("query", "maxResults", "minScore"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using RimWorld;
|
||||
@@ -12,6 +13,16 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "search_thing_def";
|
||||
public override string Description => "Rough-searches RimWorld ThingDefs by natural language (label/defName). Returns candidate defNames so you can use them in other tools like spawn_resources.";
|
||||
public override string UsageSchema => "{\"query\":\"Steel\",\"maxResults\":10,\"itemsOnly\":true}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["query"] = SchemaString("Search query.", nullable: true),
|
||||
["maxResults"] = SchemaInteger("Max candidates to return.", nullable: true),
|
||||
["itemsOnly"] = SchemaBoolean("Restrict to item defs.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("query", "maxResults", "itemsOnly"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -104,6 +104,14 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
}
|
||||
|
||||
public override string UsageSchema => "{\"units\": \"Wula_PIA_Heavy_Unit_Melee: 2, Wula_PIA_Legion_Escort_Unit: 5\"}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["units"] = SchemaString("Comma-separated list of PawnKindDef: count.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("units"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,15 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
public override string Name => "set_overwatch_mode";
|
||||
public override string Description => "Enables or disables the AI Overwatch Combat Protocol. When enabled (enabled=true), the AI will autonomously scan for hostile targets every few seconds and launch appropriate orbital bombardments for a set duration. When disabled (enabled=false), it immediately stops any active overwatch and clears the flight path. Use enabled=false to stop overwatch early if the player requests it.";
|
||||
public override string UsageSchema => "{\"enabled\":true,\"durationSeconds\":60}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["enabled"] = SchemaBoolean("Enable or disable overwatch.", nullable: true),
|
||||
["durationSeconds"] = SchemaInteger("Duration in seconds when enabling.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("enabled", "durationSeconds"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,30 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
"Otherwise, give a moderate amount. " +
|
||||
"TIP: Use the `search_thing_def` tool first and then spawn by DefName to avoid language mismatch.";
|
||||
public override string UsageSchema => "{\"items\":[{\"name\":\"Steel\",\"count\":100,\"stuffDefName\":\"Steel\"}]}";
|
||||
public override Dictionary<string, object> GetParametersSchema()
|
||||
{
|
||||
var itemProperties = new Dictionary<string, object>
|
||||
{
|
||||
["name"] = SchemaString("Thing defName or label.", nullable: true),
|
||||
["defName"] = SchemaString("ThingDef defName alias for name.", nullable: true),
|
||||
["count"] = SchemaInteger("Stack count.", nullable: true),
|
||||
["stuffDefName"] = SchemaString("Stuff defName for made-from-stuff items.", nullable: true),
|
||||
["stuff"] = SchemaString("Alias for stuffDefName.", nullable: true),
|
||||
["material"] = SchemaString("Alias for stuffDefName.", nullable: true)
|
||||
};
|
||||
var itemSchema = SchemaObject(itemProperties, RequiredList("name", "defName", "count", "stuffDefName", "stuff", "material"));
|
||||
|
||||
var properties = new Dictionary<string, object>
|
||||
{
|
||||
["items"] = SchemaArray(itemSchema, "List of items to spawn.", nullable: true),
|
||||
["name"] = SchemaString("Single item defName or label.", nullable: true),
|
||||
["count"] = SchemaInteger("Single item count.", nullable: true),
|
||||
["stuffDefName"] = SchemaString("Stuff defName for single item.", nullable: true),
|
||||
["stuff"] = SchemaString("Alias for stuffDefName.", nullable: true),
|
||||
["material"] = SchemaString("Alias for stuffDefName.", nullable: true)
|
||||
};
|
||||
return SchemaObject(properties, RequiredList("items", "name", "count", "stuffDefName", "stuff", "material"));
|
||||
}
|
||||
|
||||
public override string Execute(string args)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user