Open MMORPG by AI

Control

Bronze Baronet of the Realm
4,170
11,279
1750777971879.png


The coding was never the hard part...
 
  • 7Worf
Reactions: 6 users

Pharone

Trakanon Raider
1,329
1,182
Lmk how to have ai create lots of assets in a particular style
Yes, AI can create game assets in a specific style. Here’s how you can approach it:

1. **AI Art Generation Tools**: Use tools like MidJourney, Stable Diffusion, or DALL·E to generate 2D or 3D assets (sprites, textures, characters, environments). These tools allow you to specify styles via text prompts, such as "pixel art," "cyberpunk," or "cartoonish 3D." For example, a prompt like "medieval village in Studio Ghibli style" can produce tailored visuals. You can refine outputs by tweaking prompts or using style references (e.g., uploading an image for Stable Diffusion’s img2img feature).

2. **Style Consistency**: To maintain a cohesive style:
- **Prompt Engineering**: Use consistent descriptors (e.g., "low-poly, vibrant colors, sci-fi aesthetic") across all asset prompts.
- **Fine-Tuning Models**: Train a custom model (e.g., DreamBooth for Stable Diffusion) on a dataset of images in your desired style. This ensures uniformity.
- **Style Transfer**: Apply neural style transfer to align assets with a reference artwork’s style.

3. **3D Asset Creation**: Tools like Blender with AI plugins (e.g., Stable Diffusion add-ons) or RunwayML can generate 3D models or textures. You can also use NVIDIA’s Omniverse or Kaedim to convert 2D images into 3D models, styled as needed.

4. **Audio Assets**: AI tools like AIVA or Soundraw can generate music or sound effects in specific genres (e.g., "8-bit retro" or "epic orchestral"). Provide clear style guidelines in prompts.

5. **Code and Animation**: For animations or procedural assets, AI tools like Runway’s Gen-2 can create video-based animations, while GitHub Copilot or similar can assist in scripting behaviors in your game engine (e.g., Unity, Unreal) to match the style’s vibe.

6. **Workflow Integration**:
- **Prototyping**: Use AI to quickly mock up concept art or placeholder assets.
- **Refinement**: Edit AI-generated assets in tools like Photoshop, Blender, or Procreate to fine-tune details.
- **Game Engines**: Import assets into Unity, Godot, or Unreal Engine, ensuring they align with your game’s aesthetic (e.g., adjust lighting to match a moody cyberpunk style).

7. **Tools and Platforms**:
- **MidJourney**: Great for high-quality 2D art.
- **Stable Diffusion**: Open-source, customizable for specific styles.
- **Artbreeder**: Blend styles for characters or environments.
- **NVIDIA Canvas**: Create landscapes with painterly styles.
- **Sloyd**: AI-assisted 3D model generation with style control.

8. **Practical Tips**:
- **Reference Images**: Collect a mood board of your desired style to guide AI prompts or fine-tuning.
- **Iterate**: AI outputs may need multiple generations to nail the style—experiment with prompt variations.
- **Licensing**: Ensure AI-generated assets comply with your game’s commercial use requirements (check terms of tools like MidJourney).

If you want, I can generate a sample image in a specific style for your game (e.g., "pixel art forest" or "steampunk character"). Just confirm the style and asset type! Alternatively, I can search for more specific tools or tutorials on X or the web if you need real-time recommendations. What’s the game style you’re aiming for?
 

Pharone

Trakanon Raider
1,329
1,182
Here's a deep search answer for that...

### Key Points
- AI can likely create game assets in specific styles, with tools like Scenario and Recraft offering style customization.
- Research suggests these tools allow training custom models or using prompts for consistent aesthetics.
- The evidence leans toward AI being effective for 2D, 3D, and audio assets, but quality checks are often needed.

---

### Direct Answer

Yes, it seems likely that AI can create game assets in particular styles for game development, offering a range of tools to match your artistic vision. Here’s how it works and what you can do:

#### How AI Generates Styled Assets
AI tools like **Scenario** ([Scenario](https://www.scenario.com/:emoji_nose: and **Recraft** ([Recraft](https://www.recraft.ai/generate/game-assets:emoji_nose: allow you to generate 2D and 3D assets, such as characters, environments, and textures, by specifying the style in text prompts. For example, you might ask for "a medieval village in Studio Ghibli style" or "pixel art forest." Some tools, like Scenario, let you train custom AI models on your preferred style, ensuring consistency across assets.

For 3D assets, tools like **Sloyd** ([Sloyd](https://www.sloyd.ai/:emoji_nose: specialize in generating models with style control, while audio tools like **AIVA** can create music in genres like "8-bit retro." These assets can then be refined in software like Photoshop or Blender and imported into game engines like Unity or Unreal Engine.

#### Best Practices for Style Consistency
To get the best results, research suggests starting with clear, concise prompts (under 50 words) that specify style and details, like "{medieval knight armor} gold trim, highly detailed, game-ready asset." Begin with simpler assets like props, check model quality for issues like high polygon counts, and optimize for game performance by reducing polygons and compressing textures. Testing on target hardware ensures compatibility.

#### Tools and Tips
Popular tools include **Layer** ([Layer](https://www.layer.ai/:emoji_nose: for professional studios, **Fotor** ([Fotor](https://www.fotor.com/features/ai-game-assets-generator/:emoji_nose: for free style-consistent assets, and **Rosebud AI (PixelVibe)** ([Rosebud AI](https://lab.rosebud.ai/ai-game-assets:emoji_nose: for 2D styles like pixel art. Always check tool terms for commercial use and iterate on AI outputs for perfection.

This approach can streamline your game development, but it may require some experimentation to nail the exact style.

---

### Comprehensive Overview of AI-Generated Game Assets in Specific Styles

This section provides a detailed exploration of how AI can create game assets in particular styles, drawing from recent insights and best practices as of June 27, 2025. It covers tools, methodologies, and practical considerations for game developers aiming to leverage AI for asset creation.

#### Introduction to AI in Game Asset Creation
Artificial intelligence has revolutionized game development by enabling rapid generation of 2D and 3D assets, as well as audio, in specific artistic styles. This capability is particularly valuable for indie developers and studios looking to streamline production while maintaining a cohesive aesthetic. Tools like Scenario, Layer, and Recraft have emerged as leaders, offering features for style customization and integration into existing pipelines.

#### Tools for Generating Styled Game Assets
Several AI platforms are designed to create game assets with specific styles, catering to both novice and professional developers:

- **Scenario** ([Scenario](https://www.scenario.com/:emoji_nose:: This tool allows users to build unlimited, custom AI models by training on datasets of characters, props, and backgrounds, ensuring assets align with the art direction. It supports features like Prompt Spark for easy generation and editing tools for refining details, with case studies showing its use in cutting production time by 50% for companies like InnoGames.

- **Recraft** ([Recraft](https://www.recraft.ai/generate/game-assets:emoji_nose:: Offers a free AI game asset generator with a library of style presets and the ability to create custom styles using up to five reference images. It supports 3D fantasy characters, background textures, and scenes, making it ideal for quick prototyping.

- **Layer** ([Layer](https://www.layer.ai/:emoji_nose:: Positioned as the #1 platform for AI game asset creation, it supports 2D, 3D, video, and realtime assets, integrating seamlessly with tools like Photoshop, Blender, and Unreal Engine. While specific style creation details are less prominent, it’s designed for professional studios, trusted by over 300 leading game studios.

- **Sloyd** ([Sloyd](https://www.sloyd.ai/:emoji_nose:: Focuses on 3D asset creation, allowing users to generate models by describing style and details in prompts, such as "{medieval knight armor} gold trim, highly detailed, game-ready asset." It offers plans starting at $15/month for unlimited exports, with 30 free credits for beginners.

- **Fotor** ([Fotor](https://www.fotor.com/features/ai-game-assets-generator/:emoji_nose:: Provides a free AI game generator for high-quality, style-consistent 2D and 3D assets, with features like AI replace for editing sprites in styles like neon punk or pixel art.

- **Rosebud AI (PixelVibe)** ([Rosebud AI](https://lab.rosebud.ai/ai-game-assets:emoji_nose:: Specializes in 2D game assets, offering models for styles like pixel art portraits, cartoony items, and isometric tiles, making it intuitive for game design.

- **Meshy** ([Meshy](https://www.meshy.ai/blog/generate-3d-game-assets:emoji_nose:: A generative AI toolbox for 3D models and textures, with an intuitive interface for style customization, particularly useful for detailed environments.

- **Audio Tools**: Platforms like **AIVA** and **Soundraw** generate music and sound effects in specific genres, such as "8-bit retro" or "epic orchestral," based on user prompts, enhancing the game’s audio aesthetic.

#### Methodologies for Style-Specific Asset Generation
Creating game assets in particular styles involves several methodologies, each supported by AI tools:

1. **Prompt Engineering**: Writing clear, concise prompts is crucial for achieving the desired style. Best practices include splitting complex objects into parts (e.g., generating a "sword" and "shield" separately), keeping prompts under 50 words, and using curly brackets for must-have elements, such as "{medieval knight armor} gold trim, highly detailed, game-ready asset." Tools like Scenario’s Prompt Spark simplify this process.

2. **Custom Model Training**: Platforms like Scenario and Layer allow training AI models on specific datasets, ensuring consistency across assets. For example, uploading images of a "low-poly sci-fi" style can train the AI to generate new assets in that aesthetic.

3. **Style Transfer and References**: Some tools, like Stable Diffusion and Recraft, support style transfer by uploading reference images, aligning generated assets with a particular look, such as Studio Ghibli or cyberpunk.

4. **3D Asset Optimization**: For 3D models, tools like Sloyd emphasize starting with static props and environments, which are easier for AI to handle, before moving to characters. This approach ensures style consistency while managing complexity.

#### Best Practices for Using AI to Generate Styled Assets
To ensure high-quality, style-consistent assets, developers should follow these best practices, drawn from recent insights:

| **Best Practice** | **Details** | **Example/Notes** |
|---------------------------------|-----------------------------------------------------------------------------|-----------------------------------------------------------------------------------|
| Write Better Prompts | Split complex objects, focus on props/environments, keep under 50 words, use curly brackets for must-haves, specify style/materials | "{medieval knight armor} gold trim, highly detailed, game-ready asset"; Props: "stone well with oriental roof" |
| Check Model Quality | Review mesh structure, UV mapping, performance; allocate 30% for basic structure, 60% for technical, 90% for final testing | Use 3DS Max STL Check, UV mapping tools, game engine metrics; set aside time for 3D artist fixes |
| Make Models Run Fast | Polygon reduction (100K-200K vertices mobile), LOD implementation (3-5 versions), texture compression (1K-2K), material merging | Use Blender Decimate modifier, Unity Lightmapper; test on target hardware |
| Build Model Library | Central storage with tags/categories, version control, cloud access; compress with echo3D, mobile standards: Characters 100K poly, Props 50K, Environment 75K | Use echo3D, Daminion, Unity Cloud; organize for team collaboration |
| Ensure Compatibility | Use FBX/GLB for Unreal Engine (2GB max), Unity (4GB max); test imports, create material templates | Sloyd export in GLB works with Unity/Unreal; test to avoid issues |
| Test and Improve Models | Geometry check with 3DS Max STL Check, performance testing, fix hidden/duplicate faces, high poly with mesh rebuild | Test on target devices, match poly counts, watch performance stats |
| Add AI to Workflow | Use Unity AI add-ons, Kaedim, Sloyd; start with free tiers (Sloyd 30 credits), monitor costs; plans: Starter (0 exports), Plus ($15/month, unlimited) | Tools like Leonardo.ai (150 tokens/daily), Layer AI (unlimited for sprites); track spending |

These practices ensure assets are not only styled correctly but also optimized for game performance and compatibility.

#### Practical Considerations and Tips
- **Reference Images**: Collect a mood board of your desired style to guide AI prompts or fine-tuning, enhancing consistency.
- **Iteration**: AI outputs may require multiple generations to perfect. Experiment with prompt variations and refine using editing tools.
- **Licensing**: Check the terms of AI tools for commercial use, as some may have restrictions. For example, ensure assets comply with platform policies like Steam’s guidelines on AI-generated content.
- **Workflow Integration**: Import AI-generated assets into game engines like Unity or Unreal Engine, adjusting lighting and effects to match the game’s aesthetic.

#### Limitations and Future Outlook
While AI offers significant advantages, it’s not without challenges. AI-generated assets may need manual adjustments for high detail, and maintaining style consistency can require multiple iterations. However, with 49% of studios using AI as per the GDC 2024 survey and projections that AI will handle over half of game development by 2033, its adoption is rapidly growing. Tools are becoming more user-friendly, with affordable plans like Sloyd’s $15/month for unlimited exports, making AI accessible to indie developers.

#### Conclusion
AI can effectively create game assets in particular styles, leveraging tools like Scenario, Recraft, and Sloyd for 2D, 3D, and audio assets. By following best practices such as prompt engineering, quality checks, and performance optimization, developers can achieve high-quality, style-consistent assets, enhancing game development efficiency and creativity as of June 27, 2025.

---

### Key Citations
- [Scenario Take complete control of your AI workflows](https://www.scenario.com/)
- [Free AI game asset generator Create pro game art in seconds](https://www.recraft.ai/generate/game-assets)
- [Layer The 1 platform for AI game asset creation](https://www.layer.ai/)
- [7 Best Practices for AI-Generated 3D Models in Game Development](https://www.sloyd.ai/blog/7-best-practices-for-ai-generated-3d-models-in-game-development)
- [AI Game Generator Make 2D 3D Game Assets with AI Online Free Fotor](https://www.fotor.com/features/ai-game-assets-generator/)
- [AI Game Assets Generator PixelVibe by Rosebud AI](https://lab.rosebud.ai/ai-game-assets)
 

Pharone

Trakanon Raider
1,329
1,182
Added ability to have plugins for the server code with versioning.

I'll extend the MMORPG server code to support a modular ruleset and plugin system, allowing server administrators to enable/disable specific features (e.g., combat, inventory, chat) and select specific versions of each feature. This will be implemented in the Unity server code and the REST API, with MySQL storage for ruleset configurations. The system will:

- **Store Ruleset Configurations**: Add a MySQL table to store ruleset/plugin states (enabled/disabled) and versions.
- **Server-Side Management**: Introduce a `PluginManager` in Unity to load and manage plugins dynamically based on configuration.
- **REST API Updates**: Add endpoints to manage ruleset configurations.
- **Version Control**: Allow selection of specific plugin versions (assumed to be implemented as separate scripts or assemblies).

To keep the response concise, I'll focus on the server-side changes, integrating with the existing skeleton (including authentication, MySQL, and player management). I'll assume plugins are C# scripts or assemblies loaded dynamically, with version numbers stored as metadata.

### MySQL Database Update
Add a table to store ruleset/plugin configurations:

```sql
CREATE TABLE Rulesets (
RulesetID INT PRIMARY KEY AUTO_INCREMENT,
ServerID INT NOT NULL, -- Unique server identifier
PluginName VARCHAR(50) NOT NULL, -- e.g., "Combat", "Inventory", "Chat"
IsEnabled BOOLEAN DEFAULT TRUE,
Version VARCHAR(20) NOT NULL, -- e.g., "1.0.0", "2.0.1"
UNIQUE (ServerID, PluginName)
);
```

### Updated Unity Server Code
The Unity code is updated to include a `PluginManager` that loads plugins based on the database configuration and supports versioned plugins. I'll assume a simple plugin interface for modularity.

```x-csharp
using UnityEngine;
using Unity.Netcode;
using System.Collections;
using UnityEngine.Networking;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Reflection;

// Plugin Interface: Defines contract for plugins
public interface IGamePlugin
{
string PluginName { get; }
string Version { get; }
void Initialize();
void Shutdown();
}

// Example Plugin: Combat System
public class CombatPlugin : MonoBehaviour, IGamePlugin
{
public string PluginName => "Combat";
public string Version => "1.0.0";

public void Initialize()
{
Debug.Log("Combat Plugin v1.0.0 Initialized");
// Add combat logic (e.g., damage calculations, attack events)
}

public void Shutdown()
{
Debug.Log("Combat Plugin v1.0.0 Shutdown");
// Cleanup combat logic
}
}

// Example Plugin: Inventory System
public class InventoryPlugin : MonoBehaviour, IGamePlugin
{
public string PluginName => "Inventory";
public string Version => "1.1.0";

public void Initialize()
{
Debug.Log("Inventory Plugin v1.1.0 Initialized");
// Add inventory logic (e.g., item management)
}

public void Shutdown()
{
Debug.Log("Inventory Plugin v1.1.0 Shutdown");
// Cleanup inventory logic
}
}

// PluginManager: Manages rulesets and plugins
public class PluginManager : NetworkBehaviour
{
public static PluginManager Instance;
private Dictionary<string, IGamePlugin> activePlugins = new Dictionary<string, IGamePlugin>();
private List<RulesetConfig> rulesetConfigs = new List<RulesetConfig>();
private int serverId = 1; // Configurable server ID (set via config file or UI)

void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}

public override void OnNetworkSpawn()
{
if (IsServer)
{
StartCoroutine(LoadRulesetConfig:)emoji_nose:;
}
}

private IEnumerator LoadRulesetConfig()
{
using (UnityWebRequest request = UnityWebRequest.Get($"{GameManager.Instance.databaseManager.apiBaseUrl}/ruleset/{serverId}":emoji_nose:
{
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
rulesetConfigs = JsonConvert.DeserializeObject<List<RulesetConfig>>(request.downloadHandler.text);
LoadPlugins();
}
else
{
Debug.LogError($"Failed to load ruleset: {request.error}");
}
}
}

private void LoadPlugins()
{
// Example: Load available plugins (in practice, use Assembly.Load or ScriptableObjects)
var availablePlugins = new List<IGamePlugin>
{
gameObject.AddComponent<CombatPlugin>(),
gameObject.AddComponent<InventoryPlugin>()
};

foreach (var config in rulesetConfigs)
{
if (!config.IsEnabled) continue;

var plugin = availablePlugins.Find(p => p.PluginName == config.PluginName && p.Version == config.Version);
if (plugin != null)
{
plugin.Initialize();
activePlugins[config.PluginName] = plugin;
Debug.Log($"Loaded plugin: {config.PluginName} v{config.Version}");
}
else
{
Debug.LogWarning($"Plugin {config.PluginName} v{config.Version} not found");
}
}
}

public bool IsPluginEnabled(string pluginName)
{
return activePlugins.ContainsKey(pluginName);
}

public void ShutdownPlugins()
{
foreach (var plugin in activePlugins.Values)
{
plugin.Shutdown();
}
activePlugins.Clear();
}
}

// RulesetConfig: Structure for ruleset data
[Serializable]
public class RulesetConfig
{
public int RulesetID;
public int ServerID;
public string PluginName;
public bool IsEnabled;
public string Version;
}

// DatabaseManager: Updated with ruleset endpoints
public class DatabaseManager : MonoBehaviour
{
public static DatabaseManager Instance;
public string apiBaseUrl = "http://localhost:5000/api"; // Replace with your API URL

void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}

// Existing methods (Login, Register, LoadPlayer, SavePlayer, LoadInventory)...

public IEnumerator Login(string username, string password, Action<int, string> callback)
{
var data = new { Username = username, Password = password };
string json = JsonConvert.SerializeObject(data);
using (UnityWebRequest request = UnityWebRequest.Post($"{apiBaseUrl}/auth/login", json, "application/json":emoji_nose:
{
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
var response = JsonConvert.DeserializeObject<AuthResponse>(request.downloadHandler.text);
callback(response.PlayerID, null);
}
else
{
callback(-1, request.error);
}
}
}

public IEnumerator Register(string username, string password, Action<int, string> callback)
{
var data = new { Username = username, Password = password };
string json = JsonConvert.SerializeObject(data);
using (UnityWebRequest request = UnityWebRequest.Post($"{apiBaseUrl}/auth/register", json, "application/json":emoji_nose:
{
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
var response = JsonConvert.DeserializeObject<AuthResponse>(request.downloadHandler.text);
callback(response.PlayerID, null);
}
else
{
callback(-1, request.error);
}
}
}

public IEnumerator LoadPlayer(int playerId, Action<PlayerData> callback)
{
using (UnityWebRequest request = UnityWebRequest.Get($"{apiBaseUrl}/player/{playerId}":emoji_nose:
{
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
var data = JsonConvert.DeserializeObject<PlayerData>(request.downloadHandler.text);
callback(data);
}
else
{
Debug.LogError($"Load failed: {request.error}");
callback(null);
}
}
}

public IEnumerator SavePlayer(PlayerData data)
{
string json = JsonConvert.SerializeObject(data);
using (UnityWebRequest request = UnityWebRequest.Put($"{apiBaseUrl}/player/{data.PlayerID}", json, "application/json":emoji_nose:
{
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
{
Debug.LogError($"Save failed: {request.error}");
}
}
}

public IEnumerator LoadInventory(int playerId, Action<InventoryItem[]> callback)
{
using (UnityWebRequest request = UnityWebRequest.Get($"{apiBaseUrl}/inventory/{playerId}":emoji_nose:
{
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
var data = JsonConvert.DeserializeObject<InventoryItem[]>(request.downloadHandler.text);
callback(data);
}
else
{
Debug.LogError($"Inventory load failed: {request.error}");
callback(null);
}
}
}
}

// GameManager: Updated to include PluginManager
public class GameManager : MonoBehaviour
{
public static GameManager Instance;
public PlayerManager playerManager;
public NetworkManager networkManager;
public DatabaseManager databaseManager;
public PluginManager pluginManager;

void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}

void Start()
{
playerManager = GetComponent<PlayerManager>();
networkManager = GetComponent<NetworkManager>();
databaseManager = GetComponent<DatabaseManager>();
pluginManager = GetComponent<PluginManager>();
}

void OnDestroy()
{
if (pluginManager != null)
{
pluginManager.ShutdownPlugins();
}
}
}

// PlayerManager: Updated to check plugin status
public class PlayerManager : NetworkBehaviour
{
public GameObject playerPrefab;
private NetworkVariable<int> playerCount = new NetworkVariable<int>(0);

public override void OnNetworkSpawn()
{
if (IsServer)
{
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
}
}

private void OnClientConnected(ulong clientId)
{
// Wait for authentication
}

public void AuthenticateClient(ulong clientId, int playerId)
{
if (!IsServer) return;
StartCoroutine(SpawnPlayer(clientId, playerId:emoji_nose:;
}

private IEnumerator SpawnPlayer(ulong clientId, int playerId)
{
PlayerData data = null;
yield return GameManager.Instance.databaseManager.LoadPlayer(playerId, (result) => data = result);

if (data == null)
{
Debug.LogError($"Failed to load player data for ID {playerId}");
return;
}

Vector3 spawnPos = new Vector3(data.PosX, 0f, data.PosZ);
GameObject player = Instantiate(playerPrefab, spawnPos, Quaternion.identity);
player.GetComponent<NetworkObject>().SpawnAsPlayerObject(clientId, true);
player.GetComponent<CharacterData>().Initialize(data);
playerCount.Value++;
}
}

// PlayerController: Updated to respect plugin rules
public class PlayerController : NetworkBehaviour
{
public float moveSpeed = 5f;
private CharacterController characterController;
private Camera playerCamera;
private CharacterData characterData;

void Start()
{
characterController = GetComponent<CharacterController>();
characterData = GetComponent<CharacterData>();
if (IsOwner)
{
playerCamera = Camera.main;
playerCamera.transform.SetParent(transform);
playerCamera.transform.localPosition = new Vector3(0f, 1.5f, -3f);
}
}

void Update()
{
if (!IsOwner) return;

float moveX = Input.GetAxis("Horizontal");
float moveZ = Input.GetAxis("Vertical");
Vector3 move = transform.right * moveX + transform.forward * moveZ;
characterController.Move(move * moveSpeed * Time.deltaTime);

if (IsClient && GameManager.Instance.pluginManager.IsPluginEnabled("Combat":emoji_nose:
{
// Example: Handle combat input if plugin is enabled
if (Input.GetKeyDown(KeyCode.Space:emoji_nose:
{
AttackServerRpc();
}
}

if (IsClient)
{
UpdatePositionServerRpc(transform.position);
}
}

[ServerRpc(RequireOwnership = false)]
private void UpdatePositionServerRpc(Vector3 position)
{
transform.position = position;
characterData.UpdatePosition(position);
}

[ServerRpc]
private void AttackServerRpc()
{
// Example combat logic
Debug.Log("Player attacked!");
}
}

// CharacterData: Updated to respect plugin rules
public class CharacterData : NetworkBehaviour
{
public NetworkVariable<string> playerName = new NetworkVariable<string>("Player");
public NetworkVariable<int> health = new NetworkVariable<int>(100);
public NetworkVariable<int> level = new NetworkVariable<int>(1);
private int playerId;

public void Initialize(PlayerData data)
{
playerId = data.PlayerID;
if (IsServer)
{
playerName.Value = data.PlayerName;
health.Value = data.Health;
level.Value = data.Level;
}
if (IsOwner && GameManager.Instance.pluginManager.IsPluginEnabled("Inventory":emoji_nose:
{
StartCoroutine(LoadInventory:)emoji_nose:;
}
}

private IEnumerator LoadInventory()
{
InventoryItem[] items = null;
yield return GameManager.Instance.databaseManager.LoadInventory(playerId, (result) => items = result);
if (items != null)
{
foreach (var item in items)
{
Debug.Log($"Loaded item: {item.ItemName}, Quantity: {item.Quantity}");
}
}
}

public void UpdatePosition(Vector3 position)
{
if (!IsServer) return;
var data = new PlayerData
{
PlayerID = playerId,
PlayerName = playerName.Value,
Level = level.Value,
Health = health.Value,
PosX = position.x,
PosZ = position.z
};
StartCoroutine(GameManager.Instance.databaseManager.SavePlayer(data:emoji_nose:;
}
}

// LoginManager, NetworkSetup, PlayerData, InventoryItem, AuthResponse: Unchanged
public class LoginManager : MonoBehaviour
{
public InputField usernameInput;
public InputField passwordInput;
public Button loginButton;
public Button registerButton;
public Text errorText;
private Dictionary<ulong, int> clientToPlayerId = new Dictionary<ulong, int>();

void Start()
{
loginButton.onClick.AddListener(OnLoginClick);
registerButton.onClick.AddListener(OnRegisterClick);
}

private void OnLoginClick()
{
StartCoroutine(Login(usernameInput.text, passwordInput.text:emoji_nose:;
}

private void OnRegisterClick()
{
StartCoroutine(Register(usernameInput.text, passwordInput.text:emoji_nose:;
}

private IEnumerator Login(string username, string password)
{
int playerId = -1;
string error = null;
yield return GameManager.Instance.databaseManager.Login(username, password, (id, err) =>
{
playerId = id;
error = err;
});

if (playerId > 0)
{
errorText.text = "Login successful!";
NetworkManager.Singleton.StartClient();
clientToPlayerId[NetworkManager.Singleton.LocalClientId] = playerId;
GameManager.Instance.playerManager.AuthenticateClient(NetworkManager.Singleton.LocalClientId, playerId);
}
else
{
errorText.text = $"Login failed: {error}";
}
}

private IEnumerator Register(string username, string password)
{
int playerId = -1;
string error = null;
yield return GameManager.Instance.databaseManager.Register(username, password, (id, err) =>
{
playerId = id;
error = err;
});

if (playerId > 0)
{
errorText.text = "Registration successful! Please log in.";
}
else
{
errorText.text = $"Registration failed: {error}";
}
}

public int GetPlayerId(ulong clientId)
{
return clientToPlayerId.ContainsKey(clientId) ? clientToPlayerId[clientId] : -1;
}
}

public class NetworkSetup : MonoBehaviour
{
void Start()
{
if (NetworkManager.Singleton.IsServer)
{
NetworkManager.Singleton.StartHost();
}
}

public void StartHost()
{
NetworkManager.Singleton.StartHost();
}
}

[Serializable]
public class PlayerData
{
public int PlayerID;
public string PlayerName;
public int Level;
public int Health;
public float PosX;
public float PosZ;
}

[Serializable]
public class InventoryItem
{
public int InventoryID;
public int PlayerID;
public string ItemName;
public int Quantity;
}

[Serializable]
public class AuthResponse
{
public int PlayerID;
public string Message;
}
```

### Updated REST API
The REST API is updated to include endpoints for managing ruleset configurations.

```x-csharp
using Microsoft.AspNetCore.Mvc;
using MySqlConnector;
using System.Collections.Generic;
using System.Threading.Tasks;
using BCrypt.Net;

[ApiController]
[Route("api/[controller]")]
public class RulesetController : ControllerBase
{
private readonly string _connectionString = "Server=localhost;Database=mmorpgdb;User=root;Password=your_password;";

[HttpGet("{serverId}")]
public async Task<IActionResult> GetRuleset(int serverId)
{
using var connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
var cmd = new MySqlCommand("SELECT * FROM Rulesets WHERE ServerID = @serverId", connection);
cmd.Parameters.AddWithValue("@serverId", serverId);
using var reader = await cmd.ExecuteReaderAsync();
var rulesets = new List<RulesetConfig>();
while (await reader.ReadAsync:)emoji_nose:
{
rulesets.Add(new RulesetConfig
{
RulesetID = reader.GetInt32("RulesetID"),
ServerID = reader.GetInt32("ServerID"),
PluginName = reader.GetString("PluginName"),
IsEnabled = reader.GetBoolean("IsEnabled"),
Version = reader.GetString("Version")
});
}
return Ok(rulesets);
}

[HttpPost]
public async Task<IActionResult> CreateRuleset([FromBody] RulesetConfig config)
{
using var connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
var cmd = new MySqlCommand("INSERT INTO Rulesets (ServerID, PluginName, IsEnabled, Version) VALUES (@serverId, @pluginName, @isEnabled, @version); SELECT LAST_INSERT_ID();", connection);
cmd.Parameters.AddWithValue("@serverId", config.ServerID);
cmd.Parameters.AddWithValue("@pluginName", config.PluginName);
cmd.Parameters.AddWithValue("@isEnabled", config.IsEnabled);
cmd.Parameters.AddWithValue("@version", config.Version);
config.RulesetID = Convert.ToInt32(await cmd.ExecuteScalarAsync:)emoji_nose:;
return Ok(config);
}

[HttpPut("{rulesetId}")]
public async Task<IActionResult> UpdateRuleset(int rulesetId, [FromBody] RulesetConfig config)
{
using var connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
var cmd = new MySqlCommand("UPDATE Rulesets SET IsEnabled = @isEnabled, Version = @version WHERE RulesetID = @rulesetId", connection);
cmd.Parameters.AddWithValue("@rulesetId", rulesetId);
cmd.Parameters.AddWithValue("@isEnabled", config.IsEnabled);
cmd.Parameters.AddWithValue("@version", config.Version);
await cmd.ExecuteNonQueryAsync();
return Ok();
}
}

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly string _connectionString = "Server=localhost;Database=mmorpgdb;User=root;Password=your_password;";

[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] AuthRequest request)
{
string salt = BCrypt.Net.BCrypt.GenerateSalt();
string passwordHash = BCrypt.Net.BCrypt.HashPassword(request.Password, salt);

using var connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
var cmd = new MySqlCommand("INSERT INTO Players (PlayerName, PasswordHash, Salt, Level, Health, PosX, PosZ) VALUES (@name, @hash, @salt, @level, @health, @posX, @posZ); SELECT LAST_INSERT_ID();", connection);
cmd.Parameters.AddWithValue("@name", request.Username);
cmd.Parameters.AddWithValue("@hash", passwordHash);
cmd.Parameters.AddWithValue("@salt", salt);
cmd.Parameters.AddWithValue("@level", 1);
cmd.Parameters.AddWithValue("@health", 100);
cmd.Parameters.AddWithValue("@posX", 0f);
cmd.Parameters.AddWithValue("@posZ", 0f);
int playerId = Convert.ToInt32(await cmd.ExecuteScalarAsync:)emoji_nose:;

return Ok(new AuthResponse { PlayerID = playerId, Message = "Registered successfully" });
}

[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] AuthRequest request)
{
using var connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
var cmd = new MySqlCommand("SELECT PlayerID, PlayerName, PasswordHash, Salt FROM Players WHERE PlayerName = @name", connection);
cmd.Parameters.AddWithValue("@name", request.Username);
using var reader = await cmd.ExecuteReaderAsync();

if (await reader.ReadAsync:)emoji_nose:
{
string storedHash = reader.GetString("PasswordHash");
string salt = reader.GetString("Salt");
int playerId = reader.GetInt32("PlayerID");

if (BCrypt.Net.BCrypt.Verify(request.Password, storedHash:emoji_nose:
{
return Ok(new AuthResponse { PlayerID = playerId, Message = "Login successful" });
}
}
return Unauthorized(new AuthResponse { PlayerID = -1, Message = "Invalid credentials" });
}
}

public class AuthRequest
{
public string Username { get; set; }
public string Password { get; set; }
}

[ApiController]
[Route("api/[controller]")]
public class PlayerController : ControllerBase
{
private readonly string _connectionString = "Server=localhost;Database=mmorpgdb;User=root;Password=your_password;";

[HttpGet("{id}")]
public async Task<IActionResult> GetPlayer(int id)
{
using var connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
var cmd = new MySqlCommand("SELECT * FROM Players WHERE PlayerID = @id", connection);
cmd.Parameters.AddWithValue("@id", id);
using var reader = await cmd.ExecuteReaderAsync();
if (await reader.ReadAsync:)emoji_nose:
{
var data = new PlayerData
{
PlayerID = reader.GetInt32("PlayerID"),
PlayerName = reader.GetString("PlayerName"),
Level = reader.GetInt32("Level"),
Health = reader.GetInt32("Health"),
PosX = reader.GetFloat("PosX"),
PosZ = reader.GetFloat("PosZ")
};
return Ok(data);
}
return NotFound();
}

[HttpPut("{id}")]
public async Task<IActionResult> UpdatePlayer(int id, [FromBody] PlayerData data)
{
using var connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
var cmd = new MySqlCommand("UPDATE Players SET PlayerName = @name, Level = @level, Health = @health, PosX = @posX, PosZ = @posZ WHERE PlayerID = @id", connection);
cmd.Parameters.AddWithValue("@id", id);
cmd.Parameters.AddWithValue("@name", data.PlayerName);
cmd.Parameters.AddWithValue("@level", data.Level);
cmd.Parameters.AddWithValue("@health", data.Health);
cmd.Parameters.AddWithValue("@posX", data.PosX);
cmd.Parameters.AddWithValue("@posZ", data.PosZ);
await cmd.ExecuteNonQueryAsync();
return Ok();
}
}

[ApiController]
[Route("api/[controller]")]
public class InventoryController : ControllerBase
{
private readonly string _connectionString = "Server=localhost;Database=mmorpgdb;User=root;Password=your_password;";

[HttpGet("{playerId}")]
public async Task<IActionResult> GetInventory(int playerId)
{
using var connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
var cmd = new MySqlCommand("SELECT * FROM Inventory WHERE PlayerID = @playerId", connection);
cmd.Parameters.AddWithValue("@playerId", playerId);
using var reader = await cmd.ExecuteReaderAsync();
var items = new List<InventoryItem>();
while (await reader.ReadAsync:)emoji_nose:
{
items.Add(new InventoryItem
{
InventoryID = reader.GetInt32("InventoryID"),
PlayerID = reader.GetInt32("PlayerID"),
ItemName = reader.GetString("ItemName"),
Quantity = reader.GetInt32("Quantity")
});
}
return Ok(items);
}
}
```

### Setup Instructions
1. **MySQL Database**:
- Execute the `CREATE TABLE Rulesets` SQL to add the ruleset table.
- Populate with example data:
```sql
INSERT INTO Rulesets (ServerID, PluginName, IsEnabled, Version) VALUES
(1, 'Combat', TRUE, '1.0.0'),
(1, 'Inventory', TRUE, '1.1.0'),
(1, 'Chat', FALSE, '্র

System: * Today's date and time is 08:46 AM CDT on Friday, June 27, 2025.
 

Attachments

  • MySQL_Plugin_REST_API.txt
    8 KB · Views: 0
  • MMORPG_Plugin_System.txt
    16 KB · Views: 0

Pharone

Trakanon Raider
1,329
1,182
Thinking that the plugin system can be used to turn on/off features as well as choose which version of a feature to use if turned on.

In fact, I should have AI re-write that to be a plugin system and each plugin can have one or more features as part of that plugin.

Example:

Evil Forest Of Doom Scenario Plugin:
  • Feature: new class "necromancer"
    • class details
    • Database Install Scripts
  • Feature: New zone "Creapy ass old forest"
    • zone details
    • Database Install Scripts
  • Feature: Max level
    • Override level: integer that if higher than any other max level override rule, it becomes the max level used for the game
  • etc.

Giving all of that to AI would get you pure shit in return. Instead, you start by asking it to add a plugin system. Then you define the plug in system more. Then you add the ability to have multiple features that are part of a plugin. And, so on. Again, AI is a tool... not a developer.
 
  • 1Like
Reactions: 1 user

shabushabu

Molten Core Raider
1,415
188
This is the problem I have seen "

So let's say you are making a castle. You need the exterior and interior to match in style. I have NEVER seen this work. I can get stable diffusion / Dall-E to make portions of it, but even using the same prompt ( with the same style parts ) It never matches close enough and looks cobbled together.

Do you have an example of getting this working ?
 

shabushabu

Molten Core Raider
1,415
188
I've actually got a working D&D 5E engine and a basic action gameplay around it but I do not have the art skills to make it all environmentally styled the same. ( think wow, or eq, or Skyrim or whatever ) but in 2d. The thought of all the character sprites, environments ( indoor and outdoor ) props and then monsters ( 100s ), spell effects, Items and related animations.... looking similar in style, I just don't see how I can get AI to do it, even with techniques you say above... That said, one approach is training a custom model using textures/environments in a particular style, however you may be in copyright infringement at that point ?
 

jayrebb

Naxxramas 1.0 Raider
15,292
15,238

Pantheon's base combat and power spikes are pretty well done for an unfinished husk.

It'd be hard to see AI doing better in that area.

Where AI would beat the shit out of Pantheon is in content creation for zones. The current Pantheon team is completely creatively hamstrung (see creatively bankrupt) on zone creation despite being on Unity.
 

Pharone

Trakanon Raider
1,329
1,182
I've actually got a working D&D 5E engine and a basic action gameplay around it but I do not have the art skills to make it all environmentally styled the same. ( think wow, or eq, or Skyrim or whatever ) but in 2d. The thought of all the character sprites, environments ( indoor and outdoor ) props and then monsters ( 100s ), spell effects, Items and related animations.... looking similar in style, I just don't see how I can get AI to do it, even with techniques you say above... That said, one approach is training a custom model using textures/environments in a particular style, however you may be in copyright infringement at that point ?
I don't have an answer to this, but what I would suggest is asking a few different AIs this very question.

Ask it how to create a prompt that will give you the same style across multiple iterations.

Also, one of the things you can do with AI is ask it to make the prompt for you. This is a little trick I learned a while back that really helped. AI is actually decent at figuring out how to create the prompt that you need to use to make something. I've found that I can use something like Grok to ask it to make the prompt for me, and then copy/paste the prompt in to other AIs that are good at making things but maybe not so good at understanding what I want it to do. Grok is decent at making prompts for other systems to use.