▶️ ЗАБЕРИ СВОИ 8 ПОДАРКОВ 🎁 ПРИ СОЗДАНИИ СВОЕГО МАЙНКРАФТ СЕРВЕРА
NDS-API

NDS-API

Async-first, Redis Sync, High Performance Economy Engine for Developers.

8
0

NoieDigitalSystem API for Minecraft

A Next-Generation Economy Protocol for Minecraft Server Ecosystems

Paper Folia Java PostgreSQL Redis bStats License

NDS-API is a high-performance, async-first economy protocol designed as a modern replacement for Vault. Built with native Folia support, PostgreSQL JSONB persistence, Redis-based cross-server synchronization, and BigDecimal precision for all monetary operations.


Architecture Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                           NDS-API Architecture                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐         │
│  │   Your Plugin   │    │   Your Plugin   │    │   Your Plugin   │         │
│  └────────┬────────┘    └────────┬────────┘    └────────┬────────┘         │
│           │                      │                      │                   │
│           └──────────────────────┼──────────────────────┘                   │
│                                  ▼                                          │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │                        NDS-API Plugin Layer                           │  │
│  │  ┌─────────────────────┐    ┌─────────────────────────────────────┐   │  │
│  │  │  NdsApiPlugin       │───▶│  Shared Configuration Manager       │   │  │
│  │  │  (Entry Point)      │    │  (/plugins/NoieDigitalSystem/)      │   │  │
│  │  └─────────────────────┘    └─────────────────────────────────────┘   │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
│                                  │                                          │
│                                  ▼                                          │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │                          Core Manager Layer                           │  │
│  │  ┌─────────────────────┐    ┌─────────────────────────────────────┐   │  │
│  │  │ PlayerDigitalManager│    │ DigitalManager (Server Digitals)    │   │  │
│  │  │ (Player Currencies) │    │ + GlobalDigitalManager              │   │  │
│  │  └──────────┬──────────┘    └──────────────────┬──────────────────┘   │  │
│  │             │                                   │                      │  │
│  │             └───────────────┬───────────────────┘                      │  │
│  │                             ▼                                          │  │
│  │  ┌─────────────────────────────────────────────────────────────────┐   │  │
│  │  │                    Repository Layer (Facade)                    │   │  │
│  │  │  • Cache Manager (In-Memory + Redis)                            │   │  │
│  │  │  • JSONB Parser (PostgreSQL Native)                             │   │  │
│  │  │  • Transaction Pipeline (Optimistic Locking)                    │   │  │
│  │  └─────────────────────────────────────────────────────────────────┘   │  │
│  └───────────────────────────────────────────────────────────────────────┘  │
│                                  │                                          │
│           ┌──────────────────────┼──────────────────────┐                   │
│           ▼                      ▼                      ▼                   │
│  ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐         │
│  │   PostgreSQL    │    │     Redis       │    │   Virtual       │         │
│  │   (JSONB)       │    │   (Pub/Sub)     │    │   Threads       │         │
│  │   Primary Store │    │   Cross-Server  │    │   (Java 21)     │         │
│  └─────────────────┘    └─────────────────┘    └─────────────────┘         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Key Features

FeatureDescription
Async-First DesignAll database operations return CompletableFuture<T> for non-blocking I/O. Zero main-thread blocking.
Native Folia SupportAutomatic detection with RegionScheduler and GlobalRegionScheduler integration.
PostgreSQL JSONB BackendFlexible schema with optimistic locking (version column) for data integrity.
Redis Cross-Server SyncReal-time state synchronization via Pub/Sub channels for multi-server deployments.
BigDecimal PrecisionAll monetary operations use java.math.BigDecimal. No floating-point rounding errors.
Virtual Threads (Java 21)Leverages Project Loom's virtual threads for efficient I/O-bound operations.
Shared ConfigurationSingle config.yml shared across NDS ecosystem plugins at /plugins/NoieDigitalSystem/.
Facade Pattern ArchitectureClean separation of concerns with manager facades delegating to specialized components.

System Requirements

ComponentMinimum VersionRecommendedNotes
Java2121+Virtual threads require Java 21+
ServerPaper 1.21.4Paper/Folia 1.21.4+Folia for multi-threaded region support
PostgreSQL1215+JSONB and optimistic locking support
Redis6.07.0+Optional; required for cross-server sync
Memory512MB1GB+Varies with player count and cache size

Installation

Step 1: Download

Download the latest NoieDigitalSystem-API-x.x.x.jar from GitHub Releases.

Step 2: Deploy

Place the JAR file in your server's plugins/ directory.

Step 3: Configure

The plugin uses a shared configuration architecture. Configuration is stored at:

plugins/NoieDigitalSystem/config.yml

Minimal Required Configuration:

# PostgreSQL Connection (Required)
postgresql:
  host: "localhost"
  port: 5432
  database: "minecraft"
  username: "postgres"
  password: "your_secure_password"
  poolSize: 50

# Redis Connection (Optional - for cross-server sync)
redis:
  enabled: true
  host: "localhost"
  port: 6379
  password: ""
  timeout: 3000

Step 4: Verify

Restart the server and check for successful initialization in the console:

[NoieDigitalSystem-API] Detected server type: Folia
[NoieDigitalSystem-API] Using shared configuration at: /plugins/NoieDigitalSystem/config.yml
[NoieDigitalSystem-API] Digital Manager initialization completed.
[NoieDigitalSystem-API] NDS API Plugin enabled successfully!

Developer Integration

Dependency Setup

Gradle (Kotlin DSL)

repositories {
    mavenCentral()
}

dependencies {
    compileOnly("io.github.misty4119:noiedigitalsystem-api:2.0.0")
}

Gradle (Groovy DSL)

repositories {
    mavenCentral()
}

dependencies {
    compileOnly 'io.github.misty4119:noiedigitalsystem-api:2.0.0'
}

Maven

<dependency>
    <groupId>io.github.misty4119</groupId>
    <artifactId>noiedigitalsystem-api</artifactId>
    <version>2.0.0</version>
    <scope>provided</scope>
</dependency>

Plugin Configuration

paper-plugin.yml (Paper 1.19.4+)

name: YourPlugin
version: '1.0.0'
main: com.example.yourplugin.YourPlugin
api-version: '1.21'
dependencies:
  server:
    NoieDigitalSystem-API:
      load: BEFORE
      required: true

plugin.yml (Legacy)

name: YourPlugin
version: 1.0.0
main: com.example.yourplugin.YourPlugin
api-version: '1.21'
depend: [NoieDigitalSystem-API]

API Usage

Obtaining the API Instance

import noie.linmimeng.noiedigitalsystem.api.plugin.NdsApiPlugin;
import noie.linmimeng.noiedigitalsystem.manager.DigitalManager;
import noie.linmimeng.noiedigitalsystem.manager.PlayerDigitalManager;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;

public class YourPlugin extends JavaPlugin {
    
    private PlayerDigitalManager playerDigitalManager;
    private DigitalManager digitalManager;
    
    @Override
    public void onEnable() {
        // Obtain the NDS-API plugin instance
        Plugin ndsPlugin = getServer().getPluginManager().getPlugin("NoieDigitalSystem-API");
        
        // Validate plugin availability and type
        if (ndsPlugin == null) {
            getLogger().severe("NoieDigitalSystem-API is not installed!");
            getServer().getPluginManager().disablePlugin(this);
            return;
        }
        
        if (!(ndsPlugin instanceof NdsApiPlugin)) {
            getLogger().severe("NoieDigitalSystem-API is not the expected type!");
            getServer().getPluginManager().disablePlugin(this);
            return;
        }
        
        // Cast and obtain managers
        NdsApiPlugin ndsApi = (NdsApiPlugin) ndsPlugin;
        this.playerDigitalManager = ndsApi.getPlayerDigitalManager();
        this.digitalManager = ndsApi.getDigitalManager();
        
        getLogger().info("Successfully integrated with NoieDigitalSystem-API v2.0");
    }
}

Player Digital Operations

All player operations are asynchronous and return CompletableFuture<T>.

import java.math.BigDecimal;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

// ═══════════════════════════════════════════════════════════════════════════
// GET BALANCE
// ═══════════════════════════════════════════════════════════════════════════
CompletableFuture<BigDecimal> balanceFuture = playerDigitalManager.getDigital(playerUUID, "coins");

balanceFuture.thenAccept(balance -> {
    // Executes on async thread - DO NOT call Bukkit API directly here
    getLogger().info("Player balance: " + balance.toPlainString());
});

// ═══════════════════════════════════════════════════════════════════════════
// GIVE DIGITAL (Add to balance)
// ═══════════════════════════════════════════════════════════════════════════
BigDecimal amountToGive = new BigDecimal("100.50");

playerDigitalManager.giveDigital(playerUUID, "coins", amountToGive)
    .thenRun(() -> {
        getLogger().info("Successfully credited " + amountToGive + " coins");
    })
    .exceptionally(ex -> {
        getLogger().severe("Failed to credit coins: " + ex.getMessage());
        return null;
    });

// ═══════════════════════════════════════════════════════════════════════════
// TAKE DIGITAL (Subtract from balance)
// Returns false if insufficient balance
// ═══════════════════════════════════════════════════════════════════════════
BigDecimal amountToTake = new BigDecimal("50.00");

playerDigitalManager.takeDigital(playerUUID, "coins", amountToTake)
    .thenAccept(success -> {
        if (success) {
            getLogger().info("Successfully debited " + amountToTake + " coins");
        } else {
            getLogger().warning("Insufficient balance for debit operation");
        }
    });

// ═══════════════════════════════════════════════════════════════════════════
// SET DIGITAL (Absolute value assignment)
// ═══════════════════════════════════════════════════════════════════════════
BigDecimal newBalance = new BigDecimal("1000.00");

playerDigitalManager.setDigital(playerUUID, "coins", newBalance)
    .thenRun(() -> {
        getLogger().info("Balance set to " + newBalance);
    });

// ═══════════════════════════════════════════════════════════════════════════
// GET ALL PLAYER DIGITALS
// ═══════════════════════════════════════════════════════════════════════════
playerDigitalManager.getPlayerDigitals(playerUUID)
    .thenAccept(digitals -> {
        digitals.forEach((name, value) -> {
            getLogger().info(name + ": " + value);
        });
    });

Server Digital Operations

Server digitals are server-wide variables (e.g., world boss HP, event counters).

// ═══════════════════════════════════════════════════════════════════════════
// GET SERVER DIGITAL
// Note: This is a synchronous operation that reads from cache
// ═══════════════════════════════════════════════════════════════════════════
BigDecimal worldBossHp = digitalManager.getDigitalMap().get("world_boss_hp");

// ═══════════════════════════════════════════════════════════════════════════
// MODIFY SERVER DIGITAL (Async operations)
// ═══════════════════════════════════════════════════════════════════════════
digitalManager.giveDigital("world_boss_hp", new BigDecimal("1000"))
    .thenRun(() -> getLogger().info("World boss HP increased"));

digitalManager.takeDigital("world_boss_hp", new BigDecimal("500"))
    .thenAccept(success -> {
        if (success) {
            getLogger().info("World boss HP decreased");
        }
    });

digitalManager.setDigital("world_boss_hp", new BigDecimal("10000"))
    .thenRun(() -> getLogger().info("World boss HP reset"));

Global Player Digitals

Global digitals are currencies available to all players (e.g., "coins", "gems"). Once created, every player automatically has access to this digital type.

// ═══════════════════════════════════════════════════════════════════════════
// CREATE GLOBAL DIGITAL
// Parameters: name, initialAmount, limit (-1 = no limit)
// ═══════════════════════════════════════════════════════════════════════════
digitalManager.createGlobalDigital("gems", 0.0, -1.0)
    .thenRun(() -> {
        getLogger().info("Created global digital 'gems' - available to all players");
    });

// ═══════════════════════════════════════════════════════════════════════════
// CHECK IF GLOBAL DIGITAL EXISTS
// ═══════════════════════════════════════════════════════════════════════════
digitalManager.isGlobalDigitalExists("gems")
    .thenAccept(exists -> {
        if (exists) {
            getLogger().info("'gems' is a registered global digital");
        }
    });

// ═══════════════════════════════════════════════════════════════════════════
// GET ALL GLOBAL DIGITALS
// ═══════════════════════════════════════════════════════════════════════════
digitalManager.getGlobalDigitals()
    .thenAccept(globals -> {
        globals.forEach((name, defaultAmount) -> {
            getLogger().info("Global: " + name + " (default: " + defaultAmount + ")");
        });
    });

Error Handling Patterns

All async operations should implement proper exception handling:

playerDigitalManager.getDigital(playerUUID, "coins")
    .thenAccept(balance -> {
        // Success path
        processBalance(balance);
    })
    .exceptionally(ex -> {
        // Error path - database connection, timeout, etc.
        getLogger().severe("Database operation failed: " + ex.getMessage());
        
        // Log full stack trace for debugging
        if (getConfig().getBoolean("debug", false)) {
            ex.printStackTrace();
        }
        
        // Return null for Void-returning futures
        return null;
    });

// ═══════════════════════════════════════════════════════════════════════════
// CHAINED OPERATIONS WITH ERROR PROPAGATION
// ═══════════════════════════════════════════════════════════════════════════
playerDigitalManager.getDigital(playerUUID, "coins")
    .thenCompose(balance -> {
        if (balance.compareTo(new BigDecimal("100")) >= 0) {
            return playerDigitalManager.takeDigital(playerUUID, "coins", new BigDecimal("100"));
        }
        return CompletableFuture.completedFuture(false);
    })
    .thenAccept(success -> {
        if (success) {
            // Proceed with purchase logic
        }
    })
    .exceptionally(ex -> {
        getLogger().severe("Transaction failed: " + ex.getMessage());
        return null;
    });

Core API Reference

PlayerDigitalManager

Manages player-specific digitals (currencies, points, custom variables).

Method SignatureReturn TypeDescription
getDigital(UUID playerUUID, String digitalName)CompletableFuture<BigDecimal>Retrieves the player's balance for the specified digital. Returns BigDecimal.ZERO if not found.
setDigital(UUID playerUUID, String digitalName, BigDecimal amount)CompletableFuture<Void>Sets the player's balance to an exact value. Auto-creates the digital if it doesn't exist.
giveDigital(UUID playerUUID, String digitalName, BigDecimal amount)CompletableFuture<Void>Adds the specified amount to the player's balance. Respects configured limits.
takeDigital(UUID playerUUID, String digitalName, BigDecimal amount)CompletableFuture<Boolean>Subtracts the amount from balance. Returns false if insufficient funds. Atomic operation.
getLimit(UUID playerUUID, String digitalName)CompletableFuture<BigDecimal>Gets the maximum balance limit. Returns null if no limit is set.
setLimit(UUID playerUUID, String digitalName, BigDecimal limit)CompletableFuture<Void>Sets the maximum balance limit. Pass null to remove the limit.
getPlayerDigitals(UUID playerUUID)CompletableFuture<Map<String, Double>>Returns all digitals and their values for a player.
getPlayerDigitalLimits(UUID playerUUID)CompletableFuture<Map<String, Double>>Returns all digitals and their limits for a player.
isDigitalExists(UUID playerUUID, String digitalName)CompletableFuture<Boolean>Checks if the digital exists for the player (includes global digitals).
createDigital(UUID playerUUID, String digitalName, BigDecimal initialAmount, BigDecimal limit)CompletableFuture<Void>Creates a player-specific digital (rarely needed; auto-created on first use).
removeDigital(UUID playerUUID, String digitalName)CompletableFuture<Void>Removes a player-specific digital entry.
grantDigital(UUID playerUUID, String digitalName, BigDecimal amount)CompletableFuture<Void>Grants a special digital to a player (creates if not exists).
revokeDigital(UUID playerUUID, String digitalName)CompletableFuture<Void>Revokes/removes a digital from a player.
loadPlayerData(UUID playerUUID)CompletableFuture<Void>Pre-loads player data into cache. Called automatically on player join.
unloadPlayerData(UUID playerUUID)voidRemoves player data from memory cache. Called automatically on player quit.
clearCache()voidClears all cached player data. Use with caution.

DigitalManager

Manages server-level digitals and global player digital definitions.

Method SignatureReturn TypeDescription
getDigitalMap()Map<String, BigDecimal>Returns all server digitals and their current values (synchronous cache read).
getDigitalLimitMap()Map<String, BigDecimal>Returns all server digitals and their limits.
setDigital(String digitalName, BigDecimal amount)CompletableFuture<Void>Sets a server digital to an exact value.
giveDigital(String digitalName, BigDecimal amount)CompletableFuture<Void>Adds to a server digital's value.
takeDigital(String digitalName, BigDecimal amount)CompletableFuture<Boolean>Subtracts from a server digital. Returns false if insufficient.
removeDigital(String digitalName)CompletableFuture<Void>Removes a server digital entirely.
getLimit(String digitalName)BigDecimalGets the limit for a server digital (synchronous).
setLimit(String digitalName, BigDecimal limit)CompletableFuture<Void>Sets the limit for a server digital.
isDigitalExists(String digitalName)CompletableFuture<Boolean>Checks if a server digital exists.
renameDigital(String oldName, String newName)CompletableFuture<Void>Renames a server digital. Updates cache and Redis.

Global Digital Methods

Method SignatureReturn TypeDescription
createGlobalDigital(String digitalName, double initialAmount, double limit)CompletableFuture<Void>Creates a global digital available to all players. Pass -1 for no limit.
isGlobalDigitalExists(String digitalName)CompletableFuture<Boolean>Checks if a global digital definition exists.
removeGlobalDigital(String digitalName)CompletableFuture<Void>Removes a global digital definition. Does not delete player data.
getGlobalDigitals()CompletableFuture<Map<String, BigDecimal>>Returns all global digital definitions.
getGlobalDigitalAmount(String digitalName)CompletableFuture<BigDecimal>Gets the default amount for a global digital.
getGlobalDigitalLimit(String digitalName)CompletableFuture<BigDecimal>Gets the limit for a global digital.

Thread Safety & Concurrency

Async-First Architecture

Critical Rule: All NDS-API methods that perform I/O operations are asynchronous and return CompletableFuture<T>.

// ╔═══════════════════════════════════════════════════════════════════════════╗
// ║ CORRECT: Non-blocking async pattern                                       ║
// ╚═══════════════════════════════════════════════════════════════════════════╝
playerDigitalManager.getDigital(playerUUID, "coins")
    .thenAccept(balance -> {
        // This callback executes on a virtual thread (Java 21)
        // Safe for I/O operations, NOT safe for Bukkit API calls
        processBalanceAsync(balance);
    });

// ╔═══════════════════════════════════════════════════════════════════════════╗
// ║ INCORRECT: Blocking the main thread                                       ║
// ╚═══════════════════════════════════════════════════════════════════════════╝
// ⚠️ NEVER DO THIS - Will cause server lag/freeze
BigDecimal balance = playerDigitalManager.getDigital(playerUUID, "coins").get();

Bukkit/Paper Thread Model

When you need to interact with the Bukkit API from an async callback, you must schedule the operation on the main thread:

playerDigitalManager.getDigital(playerUUID, "coins")
    .thenAccept(balance -> {
        // Schedule Bukkit API calls on the main thread
        Bukkit.getScheduler().runTask(plugin, () -> {
            Player player = Bukkit.getPlayer(playerUUID);
            if (player != null && player.isOnline()) {
                player.sendMessage("Your balance: " + balance.toPlainString());
            }
        });
    });

Folia Region Scheduler

For Folia servers, use the entity/region scheduler instead of the global scheduler:

playerDigitalManager.getDigital(playerUUID, "coins")
    .thenAccept(balance -> {
        // For Folia: Use the entity's scheduler
        Player player = Bukkit.getPlayer(playerUUID);
        if (player != null && player.isOnline()) {
            player.getScheduler().run(plugin, scheduledTask -> {
                player.sendMessage("Your balance: " + balance.toPlainString());
            }, null);
        }
    });

Thread Model Summary:

EnvironmentCallback ThreadBukkit API Access
Bukkit/PaperVirtual Thread (async)Requires Bukkit.getScheduler().runTask()
FoliaVirtual Thread (async)Requires entity.getScheduler().run() or RegionScheduler

Data Model

Digital Types

TypeScopeUse CaseExample
Player DigitalPer-playerPlayer-specific currencies/variablesPlayer's private bank balance
Global Player DigitalDefinition → All PlayersStandard currencies everyone hascoins, gems, points
Server DigitalServer-wideWorld state, event countersworld_boss_hp, server_event_score

JSONB Structure

Player Data Example:

{
    "coins": 1500.50,
    "gems": 42,
    "stamina": 100,
    "_limits": {
        "coins": 1000000,
        "stamina": 160
    }
}

Server Data Example (uuid = '00000000-0000-0000-0000-000000000000'):

{
    "world_boss_hp": 50000,
    "event_score": 12500,
    "_global_digitals": {
        "coins": { "initial": 0, "limit": -1 },
        "gems": { "initial": 0, "limit": 9999 }
    }
}

Configuration Reference

Complete configuration with all available options:

# ═══════════════════════════════════════════════════════════════════════════
# PostgreSQL Configuration (Required)
# ═══════════════════════════════════════════════════════════════════════════
postgresql:
  host: "localhost"
  port: 5432
  database: "minecraft"
  username: "postgres"
  password: "your_secure_password"
  
  # Connection pool settings
  poolSize: 50                    # Maximum connections in pool
  connectionTimeout: 30000        # Connection timeout (ms)
  idleTimeout: 600000             # Idle connection timeout (ms)
  maxLifetime: 1800000            # Maximum connection lifetime (ms)

# ═══════════════════════════════════════════════════════════════════════════
# Redis Configuration (Optional - for cross-server sync)
# ═══════════════════════════════════════════════════════════════════════════
redis:
  enabled: true
  host: "localhost"
  port: 6379
  password: ""
  timeout: 3000
  
  # Channel prefixes for Pub/Sub
  channels:
    player: "nds:player:"
    server: "nds:server:"
    global: "nds:global:"

# ═══════════════════════════════════════════════════════════════════════════
# Digital Definitions
# ═══════════════════════════════════════════════════════════════════════════
digitals:
  coins:
    display_name: "Coins"
    persist_on_zero: false        # Delete entry when balance reaches 0
  
  gems:
    display_name: "Gems"
    persist_on_zero: true         # Keep entry even at 0 balance

# ═══════════════════════════════════════════════════════════════════════════
# Vault Integration (Compatibility Layer)
# ═══════════════════════════════════════════════════════════════════════════
vault:
  enabled: true
  enabled_digitals:
    - "coins"
  default_currency: "coins"

Protocol Specification

NDS-API is built on a cross-platform protocol specification designed for multi-language SDK support.

Protocol Domains

DomainDescription
IdentityPlayer/Server/System identity abstraction with UUID-based addressing
AssetCurrency/variable definitions with scopes (Player, Global, Server)
EventAppend-only event sourcing for immutable audit trails
TransactionAtomic operations with configurable consistency modes
ResultStandardized success/failure response envelope

Protocol Repository

For the full protocol specification, multi-language SDK documentation, and Protocol Buffers definitions:

github.com/Misty4119/nds-api


Migration from Vault

NDS-API includes a Vault compatibility layer for gradual migration.

Enabling Vault Compatibility

vault:
  enabled: true
  enabled_digitals:
    - "coins"
  default_currency: "coins"

Migration Strategy

  1. Install NDS-API alongside your existing Vault provider
  2. Enable Vault compatibility in NDS-API configuration
  3. Test thoroughly in a staging environment
  4. Migrate data using the built-in migration tools
  5. Remove legacy Vault provider once verification is complete

Troubleshooting

Common Issues

SymptomCauseSolution
NoieDigitalSystem-API not found!Plugin not installed or load order issueEnsure JAR is in plugins/ and check paper-plugin.yml dependencies
Connection pool exhaustedToo many concurrent database operationsIncrease poolSize in config; check for unclosed connections
Redis sync not workingIncorrect Redis configuration or firewallVerify Redis connection; check redis.enabled: true
ClassCastException on API accessMultiple NDS versions loadedEnsure only one NDS JAR is in plugins/
Slow performanceBlocking main thread with .get()Never use .get() on main thread; use async callbacks

Debug Mode

Enable debug logging for detailed diagnostics:

debug:
  enabled: true
  log_level: "DEBUG"
  log_sql: true

Support


License

Copyright 2024-2026 Noie Linmimeng

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

NoieDigitalSystem — Next-generation economy protocol for Minecraft.

Designed for the future. Built for today.

Совместимость

Minecraft: Java Edition

1.21.x

Платформы

Поддерживаемые окружения

Сервер

Создатели

Детали

Лицензия:Apache-2.0
Опубликован:2 месяца назад
Обновлён:1 месяц назад
Главная