Compatibility
Minecraft: Java Edition
Platforms
Supported environments
Tags
Creators
Details
- English / 2. æ¥æ¬èª
AI DataBase wAPI Core (aidbwapi_core)
A core server-side mod for Minecraft 1.21.1 (NeoForge) that provides asynchronous request functionality to external AI (OpenAI-compatible LLM APIs) and a lightweight JSON-based persistent storage (database functionality).
This mod does not provide standalone features (such as chatbots) on its own; it is designed as a system infrastructure (Core) that allows other mods (dependent mods) to easily utilize advanced AI functions and data storage via the Java API (AiCoreAPI / DatabaseManager).
ð Features & Architecture
1. AI Request Network (Advanced AI Integration & Autonomous Failover)
Equipped with an autonomous failover and rate-limiting system designed to ensure safe and reliable communication with external APIs while minimizing server load.
-
Full Async Processing & Serial Queues (Async Executor): All HTTP requests to AI are executed using
CompletableFutureand Java's standardHttpClientmechanism (asynchronous I/O), ensuring that Minecraft ticks are never blocked. Furthermore, it is designed for safety by ensuring the "number of concurrent executions is always at most one (queue management)," preventing multiple simultaneous transmissions of the same prompt string. -
Lazy Evaluation Reset (Lazy Reset): Initialization checks for "daily execution limits" and "per-minute execution limits" for models do not use periodic server tasks (constant monitoring). Instead, it adopts a Lazy Reset mechanism where calculations and resets are performed on-the-fly by comparing timestamps at the moment the next request occurs, resulting in zero standby server load.
-
Key Distribution & Distributed Round-Robin (Priority & Load Balancing): Multiple API keys can be registered for the same provider or model. You can set a priority (
priority: lower values indicate higher priority) for eachModelEntry. The system automatically falls back (switches to another model/key) to the next highest priority in the event of errors or rate limit exhaustion. Additionally, if multiple models with the same priority exist, the system distributes the requests using a "Round-Robin" method, automatically preventing load concentration on a specific API key. This allows for safe operation by aggregating rate limit quotas from multiple free API keys. -
Penalty Point (PP) System & Probabilistic Skipping (Penalty System): When communication errors occur, the model is not immediately disabled. Instead, it is assigned Penalty Points (PP) based on the severity of the error, while a temporary cooldown is applied (Default: 429 = 60s, 5xx = 120s, Timeout = 60s, Connection Failure = 300s).
HTTP 429(Rate Limited): +1 PPHTTP 5xx(Server Error): +5 PPTimeout/ Connection / DNS Failure: +7 PP- Successful Communication: Halves PP (
PP /= 2)
When selecting an execution candidate, models with PP are temporarily skipped with a probability calculated as: $$\frac{PP}{PP + 4.0}$$ The system autonomously avoids or suppresses access to endpoints that are currently unstable by moving to the next candidate.
-
100-Round Fail-Safe Loop: If all candidate models are currently in probabilistic skip or cooldown, the system loops back to the beginning of the candidate list for a re-draw. To prevent infinite loops, a robust fail-safe terminates the process after a maximum of 100 rounds, either selecting the highest priority available model (lowest priority value) as a compromise or returning a complete failure to the API layer.
-
Exception Handling (HTTP 400 Bad Request): If a configuration-related error occurs, such as
HTTP 401(Unauthorized) orHTTP 404(Model Not Found), the specific model is automatically disabled (disabled) and the system immediately falls back (retries) to the next candidate. However, forHTTP 400(Bad Request), since the issue is likely a bug specific to the prompt or data structure, switching models is unlikely to succeed. Therefore, the system returns an error immediately to the calling dependent mod without failing over (instant termination of useless loops).
2. JSON Storage System (Database Functionality)
A foundation that allows dependent mods to save and load their own data with extreme ease. The storage format is strictly fixed to JSON.
- Category Registration & Hierarchical Management:
By calling
registerCategory("my_mod")during initialization, dependent mods (external mods) automatically generate a directory structure linked to that category name. Data is automatically sorted into "General Data (Global)" and "Individual Player (UUID) Data" folders. (Note: Data cannot be saved without prior registration). - Memory Caching & Dynamic Resolution:
Frequently accessed data is cached as a Map in memory upon loading. Subsequent
get/setoperations are processed immediately without disk I/O. The root path for the storage directory is automatically determined by retrieving the correct path (e.g.,root/world/aidbwapi_core/) during theServerStartedEvent. - Synchronous & Immediate Save Mechanism:
When a write operation (
set()) is performed on the database, the memory cache is updated and an immediate synchronous file write (flush) is executed. (Note: While error logs use a background delay timer every 3 hours, the DB itself does not have an asynchronous auto-save delay feature). For safety, a manual force-save command (db save) is also implemented.
ð» Requirements & Setup
- Minecraft: 1.21.1
- Mod Loader: NeoForge 21.1.219 or later
- Java: Java 21 or higher
- Side: Required on both Server and Client
Installation:
Place this mod (aidbwapi_core-x.x.x.jar) into the mods folder of your server or client and launch.
âïž Configuration & Directory Structure
All settings, databases, and error logs are deployed in the server root directory or under saves/[world_name]/ for clients.
config/aidbwapi_core-common.toml: Basic operational settings for the entire mod.commandPermissionLevel: Required OP level for all/dbwapicommands (Default:2). Can be changed from 0 to 4.requestTimeoutSeconds: Timeout for AI communication responses (Default:60seconds).penaltyCurveFactor: Adjustment factor for the PP skip probability curve (Default:4.0).- Other settings include cooldown seconds for various HTTP errors (
rateLimitSeconds, etc.) and the periodic flush interval for error logs (flushIntervalMinutes). Some basic settings can be changed and persisted instantly via in-game commands.
config/aidbwapi_core-keynames.json: Stores AI endpoint URLs, API keys in plain text, model lists, and various rate limit settings (dailyLimit,minuteLimit) in a structured format.- â ïž [IMPORTANT] API Key Security & Registration Method
As a specification of this mod, API keys are not encrypted and are saved as plain text within this JSON file. While keys can be registered via in-game commands (
/dbwapi keyname setkey), due to Minecraft's specifications, the full command you type into the chat (the plain text API key string) will be recorded as-is in the server'slogs/latest.logand console log files. To ensure security, avoid in-game command entry. Instead, we strongly recommend opening this file directly with a text editor, editing/saving the"apiKey": "sk-xxxx..."field, and then running the/dbwapi reloadcommand in-game to reload the settings.
- â ïž [IMPORTANT] API Key Security & Registration Method
As a specification of this mod, API keys are not encrypted and are saved as plain text within this JSON file. While keys can be registered via in-game commands (
[World Save Root]/aidbwapi_core/[category_name]/: The root for settings and data storage for each category saved and cached viaCategoryDatabaseHandle, etc.global.jsonfor general data and aplayers/folder containing<UUID>.jsonfiles for individual players are placed directly under the category.
[World Save Root]/aidbwapi_core/log/: The destination where the error history (debug logs) of AI and DB processing accumulated in memory is exported in JSON format in the background.- A maximum of
20files are kept for the latest error logs by default, with older files being automatically rotated (deleted). - Any unsaved error states remaining in memory are flushed during server shutdown/termination (
ServerStoppingEvent) to ensure they are saved to disk.
- A maximum of
ð ïž Command Reference
Initial AI setup and various model settings/management can be easily performed via in-game commands.
All commands start with /dbwapi.
- Arguments & Suggestions: When entering identifiers (KeyName or Model name), suggestions (Tab completion) will be displayed for all registered settings in-game. Syntax errors or insufficient arguments will be rejected as per Brigadier standards.
- Message Format Colors: All feedback from commands starts with
[AiDb](Green). The target of the operation (values or names) is highlighted in Yellow. Errors and warnings are output in Red text. - Strict Output Protection for API Keys: When API key information is output to the chat via display commands (
infoorlist), it is masked for protection: "If the original key is 5 characters or longer, only the first 4 characters are displayed, and all remaining characters are masked with****." "If the key is 4 characters or fewer, all characters are masked with****as an exception." Raw keys are never output to the screen or logs.
ð General & Config
/dbwapi status: Summary of system operation. Displays the number of loaded KeyNames and Models, as well as the count of AI and DB errors currently queued in memory for output./dbwapi reload: Force reloads the TOML and JSON (keynames.json) configuration files. Always run this after manual text editing./dbwapi version: Displays the version of this mod./dbwapi config show: Displays the currently applied debug log settings (debugLogging) and AI communication timeout (requestTimeoutSeconds)./dbwapi config debug true|false: Instantly toggles the debug level (detailed log output) on/off and persists the setting./dbwapi config timeout <seconds>: Changes and persists the AI communication timeout (basic setting).
ð KeyName Management
Centralized management of the set consisting of the URL (provider endpoint) and API key as a system-wide "Registered Name (keyName)."
/dbwapi keyname list/info <keyName>: Displays a list of all registered KeyNames or details for a specific KeyName. (API keys are masked)./dbwapi keyname add <keyName> <apiUrl> <apiKey>: Registers a connection info set for a new AI provider (OpenAI-compatible). â» While duplicate registered names (keyName) are errors, registering the sameapiUrlandapiKeyunder different names is permitted (for load balancing)./dbwapi keyname seturl <keyName> <apiUrl>: Updates only the API endpoint URL of an existing KeyName./dbwapi keyname setkey <keyName> <apiKey>: Updates the API key of an existing KeyName. (â» Warning: Risk of log exposure. Direct JSON editing is recommended for safety.)/dbwapi keyname remove <keyName> [confirm]: Safety-locked deletion. Requirestrueat the end to execute.
ð Model & Failover Management
Model identifiers are always specified as <keyName>.<model_name> (e.g., taro_groq.llama-3-70b).
/dbwapi model list/info <keyName>.<model_name>: Displays the operational status of all models (priority, penalty/PP status, current status, etc.) and detailed limit metrics for individual models./dbwapi model add <keyName>.<model_name> [dailyLimit] [minuteLimit]: Adds a new available model to the parent KeyName. Use-1for unlimited./dbwapi model move <keyName>.<model_name> up|down: Moves/swaps the priority of a specified model one level up (up) or one level down (down)./dbwapi model limit <keyName>.<model_name> daily|minute <value>: Changes the maximum limits for a model (-1for unlimited). Changes are applied immediately./dbwapi model enable <keyName>.<model_name>/disable <keyName>.<model_name>: Enables or temporarily disables the lottery setting for a specific model.- [Recovery from Auto-Disable]: If an endpoint configuration issue occurs (e.g.,
HTTP 401/403 Invalid API KeyorHTTP 404 Not Found), the system will automatically force the model to be disabled (disabled). After resolving the mismatch (e.g., viaseturl), manually restore it using thisenablecommand.
- [Recovery from Auto-Disable]: If an endpoint configuration issue occurs (e.g.,
/dbwapi model reset <keyName>.<model_name>: Instantly resets the accumulated PP (penalty) and cooldown status of the target model to zero./dbwapi model resetall: Resets "all models" currently registered at once./dbwapi model remove <keyName>.<model_name> [confirm]: Deletes the specified model. (â» Safety lock required;trueat the end is mandatory).
ð AI Test, Error Logs, & DB Management (Tests & Logger)
/dbwapi ai status: Displays the number of AI requests currently being processed (Active) and those in the asynchronous processing wait queue (Queue)./dbwapi ai test: Uses the "currently valid model" to send a short test prompt and check if a text response actually returns./dbwapi ai errors [count]: Outputs a history of recent AI communication errors (up to 50 entries, default 10)./dbwapi ai errors clear: Clears the error history memory for display./dbwapi db list: Displays a list of all category names currently registered in theDatabaseManager./dbwapi db info <category>: Displays metrics such as the storage root path, global DB key count, and current player UUID cache count./dbwapi db errors [count]/db errors clear: Same asai errorsbut for DB-specific logs (e.g.,FILE_WRITE_ERROR)./dbwapi db save: Explicitly forces a file write (flush) of all changes in all databases in memory.
ðŠ For Developers: Java API Implementation (API Layer for Developers)
The Core infrastructure is utilized by calling it via the singleton (getInstance()) or various static methods from the Java code of your dependent mod. Please include aidbwapi_core as a dependency (e.g., compileOnly) in your build.gradle before implementing.
1. Asynchronous Request to AI (AiCoreAPI)
All internal rate-limit checks, key distribution, failovers, and exception handling pipelines are hidden.
import com.morwapi.aidbwapi_core.api.AiCoreAPI;
// Execution results are returned asynchronously as CompletableFuture<String>.
AiCoreAPI.getInstance().requestAI("Tell me the appeal of Minecraft in 100 characters")
.thenAccept(response -> {
// [On Success] Process the AI response string (response).
System.out.println("AI Response: " + response);
// â ïž [CAUTION] This is executed in a "Separate Thread (inside AsyncExecutor)".
// To safely access the Minecraft world (sending chat, placing blocks, entity operations, etc.),
// you must ensure the processing is returned to the main thread (Server Thread)
// using a task queue like server.execute(() -> { ... }).
})
.exceptionally(ex -> {
// [On Failure/Exception] Reached if all models are unavailable,
// retry limit (100) exceeded, or request parameters are invalid (HTTP 400).
System.out.println("AI Communication Error: " + ex.getMessage());
return null; // CompletableFuture requirement
});
### 2. JSON Database and Categories (`CategoryDatabaseHandle`)
Register and obtain categories via `AiCoreAPI`, and receive handles for `PlayerDatabase` or `GlobalDatabase` to save and read data.
**[IMPORTANT] JsonStorageEngine Specifications and Types:**
This database is not a high-performance ORM tool for directly saving and fully restoring complex custom class structures (POJOs). Due to GSON specifications, all data restored from JSON files via `get()` is loaded as collections of **`Map<String, Object>`** (or primitive types).
Therefore, while you can pass custom class instances when saving, the design is extremely simple and assumes you will cast or reconstruct them from Maps or standard types (or deserialize separately with GSON) when reading. Use with simple Maps, numbers, or strings is recommended.
import com.morwapi.aidbwapi_core.api.AiCoreAPI;
import com.morwapi.aidbwapi_core.api.CategoryDatabaseHandle;
import java.util.UUID;
// ------ During Mod Initialization (e.g., FMLCommonSetupEvent) ------
// [1]. Automatic generation and registration of categories
AiCoreAPI.getInstance().registerCategory("guild_mod");
// [2]. Obtaining a DB handle for operation
CategoryDatabaseHandle dbHandle = AiCoreAPI.getInstance().getCategoryDatabase("guild_mod");
// ------ Implementation Example (e.g., PlayerJoinEvent) ------
UUID playerId = player.getUUID();
// [1]. Loading data (Read)
// Restored from JSON as Map format, etc. Returns null if not created.
Object rawData = dbHandle.getPlayerDB().get(playerId, "killCount");
int killCount = 0;
if (rawData != null) {
// Since numbers may become Double due to GSON, receive as Number type and cast.
killCount = ((Number) rawData).intValue();
}
// [2]. Updating and saving data (Save)
killCount += 1;
// Arguments: Player UUID, storage identification key name, value to save (Object)
dbHandle.getPlayerDB().set(playerId, "killCount", killCount);
// â» The moment this `set()` method is called, the file is written [synchronously and immediately]
// to `guild_mod/players/<UUID>.json` at the same time it is applied to the memory (cache-side Map).
## âïž License (License)
The source code and provided binaries of this mod are provided and published under the **Apache License, Version 2.0**.
Creation and redistribution of commercial or non-commercial mods that use or depend on this infrastructure (API) are permitted freely within the scope of the license terms.
# AI DataBase wAPI Core (aidbwapi_core)
Minecraft 1.21.1 (NeoForge) åãã«ãå€éšAIïŒOpenAIäºæLLM APIïŒãžã®éåæãªã¯ãšã¹ãæ©èœãããã³JSONããŒã¹ã®è»œéãªæ°žç¶åã¹ãã¬ãŒãžïŒããŒã¿ããŒã¹æ©èœïŒãæäŸããã³ã¢ã»ãµãŒããŒãµã€ãModã§ãã
æ¬Modåäœã§å®çµããæ©èœïŒãã£ãããããçïŒã¯æãããä»ã®ModïŒäŸåModïŒãé«åºŠãªAIæ©èœãããŒã¿ä¿åæ©èœã Java API(`AiCoreAPI` / `DatabaseManager`) ãšããŠç°¡åã«å©çšã§ããããã«èšèšããã**ã·ã¹ãã åºç€ïŒCoreïŒ**ã§ãã
---
## ð ã³ã¢æ©èœãšã¢ãŒããã¯ã㣠(Features & Architecture)
### 1. AI Request Network (é«åºŠãªAI飿ºãšèªåŸåãã§ã€ã«ãªãŒããŒ)
å€éšAPIãžã®éä¿¡ãããµãŒããŒè² è·ã極éãŸã§æãã€ã€å®å
šã»ç¢ºå®ã«éçšããããã®èªåŸåãã§ã€ã«ãªãŒããŒã»ã¬ãŒããªãããã·ã¹ãã ïŒAIåäœãæ¢ããªãä»çµã¿ïŒãåããŠããŸãã
* **å®å
šéåæåŠçãšçŽåãã¥ãŒ (Async Executor):**
AIãžã®HTTPãªã¯ãšã¹ãã¯ãã¹ãŠ `CompletableFuture` ãšJavaæšæºã® `HttpClient` æ©æ§ïŒéåæI/OåŠçïŒãçšããŠå®è¡ãããMinecraftã®Tickãäžåãããã¯ããŸããããŸããåæå®è¡æ°ã¯åžžã«æå€§1ã€ãŸã§ïŒãã¥ãŒç®¡çïŒããšããåäžã®ããã³ããæååãè€æ°åæã«å€ééä¿¡ããªãå®å
šèšèšãæœãããŠããŸãã
* **é
å»¶è©äŸ¡ãªã»ãã (Lazy Reset):**
ã¢ãã«ã®ã1æ¥ãããã®å®è¡äžéãã1åãããã®å®è¡äžéãã®åæåå€å®ã¯ããµãŒããŒã®å®æåŠçïŒåžžæç£èŠïŒãè¡ãããæ¬¡åãªã¯ãšã¹ããçºçããç¬éã®ã¿ã€ã ã¹ã¿ã³ãæ¯èŒã§éœåºŠèšç®ã»ãªã»ãããããé
å»¶è©äŸ¡ïŒLazy ResetïŒãã¡ã«ããºã ãæ¡çšããŠãããåŸ
æ©äžã®ãµãŒããŒè² è·ã¯ãŒãã§ãã
* **ããŒã®åæ£éçšãšåæ£ã©ãŠã³ãããã³ (Priority & Load Balancing):**
åäžã®ãããã€ããã¢ãã«ã«å¯ŸããŠãè€æ°ã®APIããŒãç»é²ã§ããŸããã¢ãã«ïŒModelEntryïŒããšã«åªå
床(`priority`: æ°å€ãå°ããã»ã©é«åªå
)ãèšå®ã§ããã¬ãŒãäžéå°éæããšã©ãŒæã«ã¯åªå
床ã®é«ãé ãžèªåã§ãã©ãŒã«ããã¯ïŒå¥ã¢ãã«ã»å¥ããŒãžã®èªååæ¿ïŒãè¡ããŸãã
ããã«ã**åçåªå
床ã®ã¢ãã«ãè€æ°ååšããå Žåãã·ã¹ãã ã¯ãã©ãŠã³ãããã³æ¹åŒãã§è¡ãå
ã忣ãããç¹å®ã®APIããŒãžã®è² è·éäžãèªåã§é²ããŸã**ãç¡æAPIã®ã¬ãŒãå¶éæ ãè€æ°ããŒã§åç®ããŠå®å
šã«éçšããããšãå¯èœã§ãã
* **ããã«ãã£ãã€ã³ã(PP)å¶ãšç¢ºçã¹ããã (Penalty System):**
éä¿¡ãšã©ãŒçãçºçããéãå³åº§ã«å¯Ÿè±¡ã¢ãã«ãç¡å¹åããã®ã§ã¯ãªããäžæçãªã¯ãŒã«ããŠã³ç§æ°ïŒããã©ã«ã: 429=60ç§, 5xx=120ç§, Timeout=60ç§, æ¥ç¶å€±æ=300ç§ïŒã課ããšåæã«ã**ãšã©ãŒã®é倧床ã«å¿ããããã«ãã£ãã€ã³ãïŒPPïŒ**ãå ç®ããŸãã
* `HTTP 429` (ã¬ãŒãå¶é): **+1 PP**
* `HTTP 5xx` (ãµãŒããŒãšã©ãŒ): **+5 PP**
* `Timeout` / æ¥ç¶ã»DNS解決倱æ: **+7 PP**
* éä¿¡æåæ: **PPãåæž** (`PP /= 2`)
å®è¡åè£ã®éžåºæãPPãæã€ã¢ãã«ã¯ `PP / (PP + 4.0)` ã®ç¢ºçã§äžæçã«èŠéããïŒæ¬¡ç¹ã®ã¢ãã«ãžç§»è¡ïŒã調åã®æªããšã³ããã€ã³ããžã®ã¢ã¯ã»ã¹ãèªåŸçã«åé¿ã»æå¶ããŸãã
* **æå€§100åšã®ãã§ã€ã«ã»ãŒãã«ãŒã (Fail-Safe Loop):**
ãã¹ãŠã®ã¢ãã«åè£ã確çã¹ããããã¯ãŒã«ããŠã³äžã ã£ãå Žåãåè£ãªã¹ãã®å
é ã«æ»ã£ãŠåæœéžã«ãŒããçºçããŸãããç¡éã«ãŒãã鲿¢ããããã**æå€§100åšã§åŒ·å¶çã«æã¡åããå©çšå¯èœãªäžã§æãåªå
床ãé«ãïŒpriorityãå°ããïŒã¢ãã«ã劥åéžåºããããAPIå±€ãžå®å
šå€±æãè¿ã**ããšãã匷åºãªãã§ã€ã«ã»ãŒããåããŸãã
* **äŸå€åŠç (HTTP 400 Bad Request):**
`HTTP 401`ïŒèªèšŒãšã©ãŒïŒã `HTTP 404`ïŒã¢ãã«äžååšïŒã®ãããªæ§æäžè¯ãšã©ãŒãçºçããå Žåã察象ã¢ãã«èªäœãèªåç¡å¹å(`disabled`)ããäžã§çŽã¡ã«æ¬¡ã®ã¢ãã«åè£ãžãã©ãŒã«ããã¯ïŒå詊è¡ïŒããŸãããããã`HTTP 400`ïŒãªã¯ãšã¹ãäžæ£ïŒã«é¢ããŠã¯ãããã³ãããéä¿¡ããŒã¿ã®æ§é ãã®ãã®ã«ãã°ãããããããã©ã®ã¢ãã«ã«åãæ¿ããŠã倱æããå¯èœæ§ãé«ãããã§ã€ã«ãªãŒããŒãããã«å³åº§ã«åŒã³åºãå
ã®äŸåModåŽãžãšã©ãŒãè¿åŽããŸãïŒç¡é§ãªã«ãŒãã®å³ææã¡åãïŒã
### 2. JSON Storage System (ããŒã¿ããŒã¹æ©èœ)
äŸåModãç¬èªã®ããŒã¿ã極ããŠç°¡åã«ä¿åã»èªã¿åºãã§ããåºç€ã§ããä¿åãã©ãŒãããã¯**JSONå®å
šåºå®**ã§ãã
* **ã«ããŽãªã®ç»é²ãšé局管ç:**
äŸåModïŒå€éšModïŒãåæåæãªã©ã« `registerCategory("my_mod")` ãåŒã¶ããšã§ããã®ã«ããŽãªåã«çŽã¥ããã£ã¬ã¯ããªæ§æãèªåçæãããŸãããæ±çšããŒã¿ïŒGlobalïŒããšããã¬ã€ã€ãŒåå¥ïŒUUIDïŒããŒã¿ãã¯èªåã§ãã©ã«ããæ¯ãåãããä¿åãããŸããïŒâ»äºåç»é²ãè¡ããã«ããŒã¿ãä¿åããããšã¯ã§ããŸããïŒã
* **ã¡ã¢ãªãã£ãã·ã¥ãšåç解決:**
é »ç¹ã«ã¢ã¯ã»ã¹ãããããŒã¿ã¯ãèªã¿èŸŒã¿æã«ã¡ã¢ãªäžã«MapãšããŠãã£ãã·ã¥ããã以åŸã® `get` / `set` ã¯ãã£ã¹ã¯ã¢ã¯ã»ã¹ïŒI/OïŒãè¡ããå³åº§ã«åŠçãããŸããä¿åå
ãã£ã¬ã¯ããªã®ã«ãŒããã¹ã¯ããµãŒããŒèµ·åæã€ãã³ãïŒ`ServerStartedEvent`ïŒãå©çšã㊠`root/world/aidbwapi_core/` çã®æ£ãããã¹ãèªåååŸããŠæ±ºå®ããŸãã
* **åæçã»å³æã»ãŒãæ©æ§:**
ããŒã¿ããŒã¹ã«å¯Ÿããæžã蟌ã¿ïŒ`set()` ã®åŒã³åºãïŒãè¡ããããšãã¡ã¢ãªäžã®ãã£ãã·ã¥ãæŽæ°ãããã®ãšåæã«**å³åº§ã«åæçãã¡ã€ã«æžãåºãïŒãã©ãã·ã¥ïŒ**ãå®è¡ãããŸããïŒâ»ãšã©ãŒãã°åºåã®ã¿ã¯ããã¯ã°ã©ãŠã³ãã®3æéããšã®é
å»¶ã¿ã€ããŒã䜿çšããŸãããDBèªäœã«éåæãªãŒãã»ãŒãã®é
å»¶æ©èœã¯ååšããŸããïŒãå®å
šã®ãããæåã§ã®åŒ·å¶ä¿åïŒ`db save`ïŒã³ãã³ããå®è£
ãããŠããŸãã
---
## ð» åäœèŠä»¶ãšã€ã³ã¹ããŒã« (Requirements & Setup)
* **Minecraft:** 1.21.1
* **Mod Loader:** NeoForge 21.1.219 以é
* **Java:** Java 21 以äž
* **ãµã€ã:** ãµãŒããŒã»ã¯ã©ã€ã¢ã³ãäž¡æ¹å¿
é
**ã€ã³ã¹ããŒã«:**
åœMod (`aidbwapi_core-x.x.x.jar`) ããµãŒããŒãŸãã¯ã¯ã©ã€ã¢ã³ãã® `mods` ãã©ã«ãã«é
眮ããŠèµ·åããŸãã
---
## âïž èšå®ãã¡ã€ã«ãšãã£ã¬ã¯ããªæ§é (Configuration)
ãã¹ãŠã®èšå®ãããŒã¿ããŒã¹ã»ãšã©ãŒãã°ã¯ããµãŒããŒã®ã«ãŒããã£ã¬ã¯ããªããŸãã¯ã¯ã©ã€ã¢ã³ãã® `saves/[ã¯ãŒã«ãå]/` é
äžã«å±éãããŸãã
* **`config/aidbwapi_core-common.toml`** : Modå
šäœã®åºç€åäœèšå®ãã¡ã€ã«ã
* `commandPermissionLevel`: å
šãŠã® `/dbwapi` ã³ãã³ãã®èŠæ±OPæš©éã¬ãã«ïŒããã©ã«ã `2`ïŒã0ã4ã«å€æŽå¯èœã§ãã
* `requestTimeoutSeconds`: AIéä¿¡ã®å¿çã¿ã€ã ã¢ãŠãç§æ°ïŒããã©ã«ã `60`ç§ïŒã
* `penaltyCurveFactor`: PPã¹ããã確çèšç®æ²ç·ã®èª¿æŽä¿æ°ïŒããã©ã«ã `4.0`ïŒã
* ä»ãåçš®HTTPãšã©ãŒæã®ã¯ãŒã«ããŠã³ç§æ°ïŒ`rateLimitSeconds` çïŒãããšã©ãŒãã°ã®å®æãã©ãã·ã¥ééïŒ`flushIntervalMinutes`ïŒçãèšå®å¯èœãäžéšã®åºç€èšå®ã¯ã€ã³ã²ãŒã ã³ãã³ãïŒ`/dbwapi config ...` çïŒããã§ãå³åº§ã«å€æŽã»æ°žç¶åãããŸãã
* **`config/aidbwapi_core-keynames.json`** : AIãšã³ããã€ã³ãURLãAPIããŒã®å¹³æãããã³ã¢ãã«äžèЧãšåçš®ã¬ãŒãå¶é(`dailyLimit`, `minuteLimit`)ã®èšå®ãæ§é åä¿åãããŸãã
* **â ïžãéèŠãAPIããŒã®ã»ãã¥ãªãã£ã»ç»é²æ¹æ³ã«ã€ããŠ**
Modã®ä»æ§ãšããŠAPIããŒèªäœã¯æå·åãããããã®JSONãã¡ã€ã«å
ã«å¹³æã§ä¿åãããŸãïŒ`.gitignore` çã§ã®é²è¡ãOSãµãŒããŒæš©éã«ããä¿è·éçšãåæãšããŠããŸãïŒãã€ã³ã²ãŒã ã®ã³ãã³ãïŒ`/dbwapi keyname setkey`ïŒããã§ãç»é²å¯èœã§ããã**Minecraftã®ä»æ§äžãããªãããã£ããæ¬ã«æã¡èŸŒãã ã³ãã³ãå
šæïŒAPIããŒã®å¹³ææååïŒã¯ããµãŒããŒã® `logs/latest.log` ãã³ã³ãœãŒã«ç»é¢ã®ãã°ãã¡ã€ã«ã«ãã®ãŸãŸäžžèŠãã§èšé²ãããŠããŸããŸãã**
ã»ãã¥ãªãã£ãæ
ä¿ãããããå€éšã«æäŸãããå¯èœæ§ã®ãããµãŒããŒãéçšããå Žåãã²ãŒã å
ã§ã®ã³ãã³ãå
¥åã¯é¿ãã**æ¬ãã¡ã€ã«ãçŽæ¥ããã¹ããšãã£ã¿ã§éã `"apiKey": "sk-xxxx..."` ãæžãæãã»ä¿åããããã§ãã²ãŒã å
ã§ `/dbwapi reload` ã³ãã³ããå®è¡ããŠåèªã¿èŸŒã¿ãããéçšãåŒ·ãæšå¥šããŸãã**
* **`[ã¯ãŒã«ãä¿åã«ãŒã]/aidbwapi_core/[ã«ããŽãªå]/`** : `CategoryDatabaseHandle` çãçµç±ããŠä¿åã»ãã£ãã·ã¥ãããåã«ããŽãªã®èšå®ã»ããŒã¿ä¿åã«ãŒãã
* ã«ããŽãªçŽäžã«æ±çšããŒã¿ïŒ`global.json`ïŒãšããã¬ã€ã€ãŒåå¥ãã©ã«ãïŒ`players/<UUID>.json`ïŒãé
眮ãããŸãã
* **`[ã¯ãŒã«ãä¿åã«ãŒã]/aidbwapi_core/log/`** : ã¡ã¢ãªäžã«èç©ãããAIã»DBåŠçæã®ãšã©ãŒå±¥æŽïŒãããã°ãã°ïŒãããã¯ã°ã©ãŠã³ãã§JSON圢åŒåºåãããåºåå
ã
* ææ°ã®ãšã©ãŒãã°åºåã¯ããã©ã«ãã§æå€§ `20` ãã¡ã€ã«ä¿æãããå€ããã®ããèªåããŒããŒã·ã§ã³ïŒåé€ïŒãããŸãã
* ãŸããã¡ã¢ãªã«æ®åããæªä¿åã®ãšã©ãŒç¶æ
ã¯ããµãŒããŒçµäºã»ã·ã£ããããŠã³æïŒ`ServerStoppingEvent`ïŒã«å²ã蟌ã¿ã§ãã©ãã·ã¥ããã確å®ã«ãã£ã¹ã¯ãžææžã»ä¿åãããŸãã
---
## ð ïž ã³ãã³ããªãã¡ã¬ã³ã¹ (Command Reference)
AIã®åæã»ããã¢ãããã¢ãã«ã®åçš®èšå®ã»ç®¡çã¯ãã€ã³ã²ãŒã ã³ãã³ãããæè»œã«è¡ããŸãã
ãã¹ãŠã®ã³ãã³ã㯠`/dbwapi` ã§å§ãŸããŸããïŒããã©ã«ãèŠæ±æš©é: `common.toml` èšèŒã®ã¬ãã«ãåæå€ã¯2ïŒ
* **åŒæ°ã»ãµãžã§ã¹ãã®ä»æ§:** èå¥åïŒKeyNameãModelåïŒãå
¥åããéãç»é²æžã¿ã®èšå®ãã¹ãŠãã€ã³ã²ãŒã ã§ãµãžã§ã¹ãïŒTabè£å®ïŒè¡šç€ºãããŸããæ§æãšã©ãŒãåŒæ°äžè¶³ã¯BrigadieræšæºãšããŠåŒŸãããŸãã
* **ã¡ãã»ãŒãžãã©ãŒããã衚瀺è²:** ã³ãã³ãããã®ãã£ãŒãããã¯ã¯ãã¹ãŠã·ã¹ãã ã¡ãã»ãŒãžãšã㊠`[AiDb]` (ç·è²) ããå§ãŸããæäœå¯Ÿè±¡ïŒæ°å€ãååïŒã¯é»è²ã§ãã€ã©ã€ããããŸãããšã©ãŒãèŠåã¯å
šäœãèµ€è²ããã¹ãã§åºåãããŸãã
* **APIããŒçã®åºåä¿è·ã®åŸ¹åº:** ç»é¢è¡šç€ºçšã³ãã³ãïŒ`info` ã `list`ïŒçã§APIããŒæ
å ±ããã£ããã«åºåãããéã¯ãä¿è·ã®ãããå
ã®ããŒã5æå以äžã®å Žåã¯**å
é 4æåã®ã¿è¡šç€ºããæ®ãã®å
šæåã `****` ã«ãã¹ãã³ã°**ããå
ã®ããŒã4æå以äžã®å Žåã¯**äŸå€ãšããŠå
šæåã `****` ã«ãã¹ãã³ã°**ãããç¶æ
ã§ã®ã¿è¡šç€ºãããçããŒãç»é¢ã«åºåãããããšã¯çµ¶å¯Ÿã«ãããŸããããŸããã·ã¹ãã ãã°ã®åºåæãªã©ã«ãããŒã¯äžåå«ãŸããŸããã
### ð å
šè¬ (General & Config)
* `/dbwapi status` : ã·ã¹ãã å
šäœã®çšŒåãµããªãŒãããŒãæžã¿ã®KeyNameæ°ãšã¢ãã«æ°ã«å ããã¡ã¢ãªäžã§åºååŸ
æ©ç¶æ
ïŒQueueïŒã«ãªã£ãŠããAIãšã©ãŒã»DBãšã©ãŒã®ä»¶æ°ã衚瀺ããŸãã
* `/dbwapi reload` : TOMLããã³JSONïŒ`keynames.json`ïŒèšå®ãã¡ã€ã«ã匷å¶çã«åèªã¿èŸŒã¿ããŸããããã¹ãæåç·šéæã¯å¿
ãå®è¡ããŠãã ããã
* `/dbwapi version` : åœModã®ããŒãžã§ã³ã衚瀺ããŸãã
* `/dbwapi config show` : çŸåšé©çšãããŠãããããã°ãã°èšå®ïŒ`debugLogging`ïŒãšAIéä¿¡ã¿ã€ã ã¢ãŠãç§æ°ïŒ`requestTimeoutSeconds`ïŒã衚瀺ããŸãã
* `/dbwapi config debug true|false` : ãããã°ã¬ãã«ïŒè©³çްãã°åºåïŒã®ãªã³/ãªããå³åº§ã«åãæ¿ãã»æ°žç¶åããŸãã
* `/dbwapi config timeout <ç§>` : AIéä¿¡ã®ã¿ã€ã ã¢ãŠãç§æ°ïŒåºç€èšå®ïŒã倿Žã»æ°žç¶åããŸãã
### ð ããŒ(KeyName)管ç (KeyName Management)
URLïŒãããã€ããšã³ããã€ã³ãïŒãšAPIããŒã®ã»ããããã·ã¹ãã å
±éã®**ãç»é²å(keyName)ã**ãšããŠäžå
管çããŸãã
* `/dbwapi keyname list` / `info <keyName>` : ç»é²æžã¿ã®å
šKeyNameã®äžèЧããŸãã¯æå®ããKeyNameã®è©³çްã衚瀺ããŸããïŒAPIããŒã¯ãã¹ã¯ãããŸãïŒ
* `/dbwapi keyname add <keyName> <apiUrl> <apiKey>` : æ°ããAIãããã€ãïŒOpenAIäºæïŒã«å¯Ÿããæ¥ç¶æ
å ±ã»ãããç»é²ããŸããâ»ç»é²å(`keyName`)ã®éè€ã¯ãšã©ãŒã§ããã`apiUrl` ãš `apiKey` ã«åäžã®å
容ãå¥åã§è€æ°ç»é²ããããšã¯èš±å¯ãããŠããŸãïŒè² è·åæ£ã®ããïŒã
* `/dbwapi keyname seturl <keyName> <apiUrl>` : æ¢åã®KeyNameã®APIãšã³ããã€ã³ãURLã®ã¿ãæŽæ°ããŸãã
* `/dbwapi keyname setkey <keyName> <apiKey>` : æ¢åã®KeyNameã®APIããŒãæŽæ°ããŸãã**(â»åè¿°ã®ãã°æ®åãªã¹ã¯ããããŸããå®å
šã®ããJSONã®çŽæ¥ç·šéãæšå¥šããŸãã)**
* `/dbwapi keyname remove <keyName> [confirm]` : 誀æäœé²æ¢ã®å®å
šè£
眮ä»ãåé€ãæ«å°ŸåŒæ°ïŒ`[confirm]`ïŒãçç¥ãŸã㯠`false` ã§å®è¡ããå Žåã¯ãåé€ç¢ºèªã®èŠåãã°ã®ã¿åºåããŠçµäºããŸããæ«å°Ÿã«æç€ºçã« `true` ãæå®ããå Žåã®ã¿ãKeyNameïŒããã³ãã®KeyNameã«çŽã¥ããã¹ãŠã®ã¢ãã«èšå®çŸ€ïŒãå®å
šã«åé€ãããŸãã
### ð ã¢ãã«ç®¡ç (Model & Failover Management)
ã¢ãã«ã®èå¥åã¯ãã©ã®ãããã€ãã®ã¢ãã«ããåããããã«ãåžžã« **`<keyName>.<ã¢ãã«å>`**ïŒäŸ: `taro_groq.llama-3-70b` ã®ããã«ãããã§åºåãïŒã§æå®ããŸãã
* `/dbwapi model list` / `info <keyName>.<ã¢ãã«å>` : å
šã¢ãã«ã®çšŒåç¶æ³ïŒåªå
床ãããã«ãã£ã»PPç¶æ³ãçŸåšæå¹ãçïŒããåå¥ã¢ãã«ã®è©³çްãªå¶éã¡ããªã¯ã¹ã衚瀺ããŸãã
* `/dbwapi model add <keyName>.<ã¢ãã«å> [dailyLimit:æ¥æ¬¡äžé] [minuteLimit:åéäžé]` : 芪ãšãªãKeyNameã«å¯ŸããŠæ°ããå©çšå¯èœã¢ãã«ã远å ããŸããäžéå€åŒæ°ãçç¥ããå ŽåããŸã㯠`-1` ãå
¥åããå Žåã¯ãæ¥æ¬¡/忬¡ãšãã«ç¡å¶éããšããŠç»é²ãããŸãã
* `/dbwapi model move <keyName>.<ã¢ãã«å> up|down` : æå®ã¢ãã«ã®åªå
床ïŒPriorityé äœïŒãã1ã€äžïŒ`up`ïŒãŸã㯠1ã€äžïŒ`down`ïŒã«ç§»åã»å
¥ãæ¿ããŸãã
* `/dbwapi model limit <keyName>.<ã¢ãã«å> daily|minute <å€>` : ã¢ãã«ã®äžéåæ°ã倿ŽããŸãïŒ`-1` ã§ç¡å¶éïŒãèšå®ã®å€æŽã¯å³æé©çšãããŸãã
* `/dbwapi model enable <keyName>.<ã¢ãã«å>` / `disable <keyName>.<ã¢ãã«å>` : æå®ã¢ãã«ã®æœéžèšå®ãæå¹å/äžæç¡å¹åããŸãã
* **ãèªåç¡å¹åããã®åŸ©æ§ã**: äŸå€(`HTTP 401/403 Invalid API Key` ã `HTTP 404 Not Found`) ãªã©ãæä¹
çã«å€±æããèšå®åé¡ãçºèŠããå Žåãã·ã¹ãã ã察象ã¢ãã«ãèªåçã«åŒ·å¶ç¡å¹å(`disabled`)ããŸãããšã³ããã€ã³ãã®äžæŽåçãè§£æ¶ïŒ`seturl` çïŒããåŸããã® `enable` ã³ãã³ãã§æå埩垰ãããŠãã ããã
* `/dbwapi model reset <keyName>.<ã¢ãã«å>` : 察象ã¢ãã«ã®èç©ãããPP(ããã«ãã£)ããã¯ãŒã«ããŠã³ç¶æ
ãå³åº§ã«ãŒãã«ãªã»ããããŸãã
* `/dbwapi model resetall` : çŸåšç»é²ãããŠãããå
šã¢ãã«ããäžæã«ãªã»ããããŸãã
* `/dbwapi model remove <keyName>.<ã¢ãã«å> [confirm]` : æå®ã¢ãã«ãåé€ããŸããïŒâ»å®å
šè£
眮ãããæ«å°Ÿã« `true` ãå¿
é ã§ãïŒ
### ð AIåäœãã¹ãã»ãšã©ãŒãã°ã»DB管ç (Tests & Logger)
* `/dbwapi ai status` : çŸåšå®è¡ã»åŠçäžã®ïŒ`Active`ïŒãªã¯ãšã¹ããšãéåæåŠçã®åŸ
æ©ãã¥ãŒïŒ`Queue`ïŒã«å
¥ã£ãŠããAIãªã¯ãšã¹ãã®ä»¶æ°ã衚瀺ããŸãã
* `/dbwapi ai test` : ãçŸåšæå¹ãªã¢ãã«ïŒæãåªå
床ãé«ããéä¿¡å¯èœãªãã®ïŒããå©çšããŠãã·ã¹ãã ããæ°åæåã®çããã¹ãããã³ãããAIã«éä¿¡ããå®éã«ããã¹ãã®è¿çãæ¥ããã©ããã®çéïŒçµåïŒãã¹ããè¡ããŸãã
* `/dbwapi ai errors [衚瀺件æ°]` : ãã¥ãŒã«èç©ãããŠãããçŽè¿ã§çºçããAIéä¿¡ãšã©ãŒïŒHTTPã¹ããŒã¿ã¹ã³ãŒããåå äŸå€çïŒãã®å±¥æŽãæéã»å¯Ÿè±¡ã¢ãã«åãšãšãã«æå€§50ä»¶ïŒçç¥æã¯ããã©ã«ã10ä»¶ïŒãã£ããæ¬ã«çŽ æ©ãåºåããŸãããšã©ãŒã®ç¹å®ã«äŸ¿å©ã§ãã
* `/dbwapi ai errors clear` : ç»é¢è¡šç€ºçšã®ãšã©ãŒå±¥æŽã¡ã¢ãªã空ã«ããŸããïŒâ»ãã£ã¹ã¯äžã®ãã°ãã¡ã€ã«èªäœã¯åé€ãããŸããïŒ
* `/dbwapi db list` : äŸåModçãã `DatabaseManager` ã«çŸåšç»é²ãããŠããå
šã«ããŽãªåã®äžèЧã衚瀺ããŸãã
* `/dbwapi db info <ã«ããŽãªå>` : 察象ã«ããŽãªã®ä¿åå
ã«ãŒããã¹ãã°ããŒãã«DBã®ããŒæ°ïŒããŒãæžã®èŠæš¡æïŒãããã³çŸåšãã£ãã·ã¥ã«ä¹ã£ãŠãããã¬ã€ã€ãŒæ¯ã®UUIDããŒã¿ã®ç·æ°ãªã©ã®ã¡ããªã¯ã¹ã衚瀺ããŸãã
* `/dbwapi db errors [ä»¶æ°]` / `db errors clear` : `ai errors` ãšåãä»çµã¿ã§ãDBç¹æã®ãã°ïŒ`FILE_WRITE_ERROR` çïŒããã£ããã«åºåïŒçç¥æã¯ããã©ã«ã10ä»¶ïŒã»ã¯ãªã¢ããŸãã
* `/dbwapi db save` : ã¡ã¢ãªäžã®å
šããŒã¿ããŒã¹ã®å€æŽå
容ãæç€ºçã«åŒ·å¶ãã¡ã€ã«æžãåºãïŒãã©ãã·ã¥ïŒãããŸããïŒâ»é垞㯠`set` æã«èªåã§å³æåæä¿åããããããçŽæ¥ã¡ã¢ãªãæ¹ããããå Žåã®ææžçšã§ãïŒã
---
## ðŠ éçºè
åã: Java APIã®å®è£
å©ç𿹿³ (API Layer for Developers)
åœCoreåºç€ã¯ãäŸåModïŒèªäœModçïŒã® Java ã³ãŒããããã·ã³ã°ã«ãã³ïŒ`getInstance()`ïŒãŸãã¯åçš® Static ã¡ãœããçµç±ã§åŒã³åºããŠå©çšããŸãã`build.gradle` ã§ `aidbwapi_core` ãäŸå解決ïŒ`compileOnly` çïŒã«å«ããäžã§å®è£
ããŠãã ããã
### 1. AIãžã®éåæãªã¯ãšã¹ã (`AiCoreAPI`)
å
éšã§ã®ã¬ãŒãå¶éãã§ãã¯ãããŒã®æ¯ãåãããã©ãŒã«ããã¯ãäŸå€ãã³ããªã³ã°ãã€ãã©ã€ã³ããã¹ãŠé èœããŠããŸãã
åŒã³åºãåŽã®éçºè
ã¯ãããã³ããæååãæããŠãCompletableFuture ã§çµæã®æååãåãåããã ãã§å®çµããéåžžã«ã·ã³ãã«ãªèšèšãšããŠæ©èœããŸãã
```java
import com.morwapi.aidbwapi_core.api.AiCoreAPI;
// CompletableFuture<String> ãšããŠå®è¡çµæãéåæã«è¿åŽãããŸãã
AiCoreAPI.getInstance().requestAI("Minecraftã®é
åã100æåã§æããŠ")
.thenAccept(response -> {
// [æåææ³å®] AIã®ã¬ã¹ãã³ã¹æåå(response)ãååŸããŠåŠçã
System.out.println("AIã®åç: " + response);
// â ïžã泚æãããã¯ãå¥ã¹ã¬ãã(AsyncExecutorå
éš)ãã§å®è¡ãããŠããŸãã
// ãã€ã¯ã©ã®äžç(ãã£ããéä¿¡ããããã¯èšçœ®ããšã³ãã£ãã£æäœç)ãžå®å
šã«ã¢ã¯ã»ã¹ããããã«ã¯ã
// å¿
ã server.execute(() -> { ... }) çã®ã¿ã¹ã¯ãã¥ãŒãçšããŠ
// åŠçãã¡ã€ã³ã¹ã¬ãã(Server Thread)ãžç¢ºå®ã«æ»ããŠãã ããã
})
.exceptionally(ex -> {
// [倱ææã»äŸå€æ] ç»é²ãããŠããå
šã¢ãã«ã䜿çšäžå¯ïŒå
šæ»
ïŒãããªãã©ã€100ä»¶è¶
éã
// ãããã¯ãªã¯ãšã¹ããã©ã¡ãŒã¿äžæ£(HTTP 400)çã§å®å
šå€±æããå Žåã«å°éããŸãã
// ãšã©ãŒã®çš®å¥(RATE_LIMITED, ALL_FAILEDç)ã詳现ãã¡ãã»ãŒãž(ex.getMessage())ã«å«ãŸããŸãã
System.out.println("AIéä¿¡ãšã©ãŒ: " + ex.getMessage());
return null; // CompletableFutureèŠä»¶
});
2. JSONããŒã¿ããŒã¹ãšã«ããŽãª (CategoryDatabaseHandle)
AiCoreAPI ãçµç±ããŠã«ããŽãªãç»é²ã»ååŸããPlayerDatabase ãŸã㯠GlobalDatabase ã®ãã³ãã«ãåãåã£ãŠããŒã¿ã®ä¿åã»èªåºãè¡ããŸãã
ãéèŠãJsonStorageEngineã®ä»æ§ãšå:
åœDBã¯ãç¬èªã®è€éãªã¯ã©ã¹æ§é ïŒPOJOïŒãçŽæ¥ä¿åã»å®å
šåŸ©å
ãã髿©èœORMããŒã«ã§ã¯ãããŸãããGsonã®ä»æ§çã«ãããJSONãã¡ã€ã«ãã get() ã§å±éïŒåŸ©å
ïŒãããããŒã¿ã¯ãã¹ãŠ Map<String, Object>ïŒãããã¯ããªããã£ãåïŒã®ã³ã¬ã¯ã·ã§ã³ãšããŠããŒããããŸãã
ãã®ãããä¿åæã¯èªåã§ç¬èªã¯ã©ã¹ã€ã³ã¹ã¿ã³ã¹ãæž¡ãããšãå¯èœã§ãããèªèŸŒæã¯Mapãæšæºåããèªåã§ãã£ã¹ãã»åæ§ç¯ïŒãããã¯å¥éGsonã§ã®ãã·ãªã¢ã©ã€ãºïŒãè¡ãåæã®ã極ããŠã·ã³ãã«ãªæ©èœèšèšãšãªã£ãŠããŸããåçŽãªMapãæ°å€ãæååããŒã¹ã§ã®å©çšãæšå¥šããŸãã
import com.morwapi.aidbwapi_core.api.AiCoreAPI;
import com.morwapi.aidbwapi_core.api.CategoryDatabaseHandle;
import java.util.UUID;
// ------ Modã®åæåæ (FMLCommonSetupEventç) ------
// [1]. ã«ããŽãªã®èªåçæã»ç»é²
AiCoreAPI.getInstance().registerCategory("guild_mod");
// [2]. æäœçšDBãã³ãã«ã®ååŸ
CategoryDatabaseHandle dbHandle = AiCoreAPI.getInstance().getCategoryDatabase("guild_mod");
// ------ å®è£
äŸ (PlayerJoinEventç) ------
UUID playerId = player.getUUID();
// [1]. ããŒã¿ã®ããŒã (èªã¿èŸŒã¿)
// JSONããMap圢åŒçã§åŸ©å
ãããŸããæªäœæã®å Žå㯠null ãè¿ããŸãã
Object rawData = dbHandle.getPlayerDB().get(playerId, "killCount");
int killCount = 0;
if (rawData != null) {
// Gsonã«ããæ°å€ã¯Doubleçã«ãªãå ŽåããããããNumberåã§åãåããã£ã¹ãããŸã
killCount = ((Number) rawData).intValue();
}
// [2]. ããŒã¿ã®æŽæ°ãšã»ãŒã (ä¿å)
killCount += 1;
// åŒæ°: ãã¬ã€ã€ãŒUUID, ä¿åèå¥ããŒå, ä¿åããå€(Object)
dbHandle.getPlayerDB().set(playerId, "killCount", killCount);
// â»ãã® `set()` ã¡ãœãããåŒãã ç¬éã«ãã¡ã¢ãª(ãã£ãã·ã¥åŽã®Map)ãžã®é©çšãšåæã«ã
// `guild_mod/players/<UUID>.json` ãžãåæçãã€å³åº§ã«ããã¡ã€ã«ãæžãåºãããŸãã
âïž ã©ã€ã»ã³ã¹ (License)
ãã®Modã®ãœãŒã¹ã³ãŒãããã³æäŸããããã€ããªã¯ Apache License, Version 2.0 ã§æäŸã»å ¬éãããŠããŸãã æ¬åºç€ïŒAPIïŒãå©çšã»äŸåããåçšã»éåçšModã®äœæããã³åé åžã¯ãã©ã€ã»ã³ã¹æ¡é ã®ç¯å²å ã§èªç±ã«è¡ã£ãŠããã ããŸãã

