Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@EmanuelCatania
Copy link

  • Summary: This PR contributes the main improvements from the OpenMU‑S2 fork: adds English/Spanish localization, enhances the Admin Panel (including log tailing), refactors and fixes summon behavior, adds event data (Rena, Golden Archer, White Wizard), improves logging and Docker setups, and updates docs and tests.

  • Highlights by area:

    • Localization: New src/Localization project with JSON resources (strings.en.json, strings.es.json); Admin Panel localization with LanguageSelector and localized components/files under src/Web/AdminPanel/Localization.

    • Admin Panel: New pages and widgets (e.g., Craftings.razor, LogTail.razor, LogTailWidget.razor), improved tables and navigation, style tweaks, and UX fixes across multiple .razor pages.

    • Summon logic: Refactor to allow a single configuration plug‑in to customize all summons; fix self‑defense interaction with own summon; expanded logging for summon behavior.

    • Gameplay fixes: Multiple fixes in crafting, inventory, trade, dup prevention, zen handling, NPC interactions, and attribute calculations across src/GameLogic/*.

    • Event/data updates: Add/update data and initialization for Rena global drop, Golden Archer, and White Wizard; adjust UpdateVersion to include new updates and keep upstream values intact.

    • Plug‑ins and commands: New AutoBroadcastMessagesPlugIn; additional chat command capabilities (e.g., item stack command args and handling).

    • Networking: Packet updates for item crafting result and related server‑to‑client definitions.

    • Startup & logging: In‑memory log buffer/sink and console logging utilities under src/Startup/Logging; Program.cs and appsettings.json adjustments to surface logs and improve diagnostics.

    • Docker: Multiple compose variants and overlays for local/public/LAN and with/without NGINX (deploy/all-in-one/*), plus admin‑port override.

    • Docs: Updated README.md, QuickStart.md, and added docs for events and summon/logging (docs/*).

    • Solution: Added src/Localization/MUnique.OpenMU.Localization.csproj and updated src/MUnique.OpenMU.sln.

    • Tests: Added tests/MUnique.OpenMU.Tests/SelfDefensePlugInTest.cs, updated packet tests.

  • Breaking changes / migration:

    • Database initialization updates extended (via UpdateVersion and new update plug‑ins). Existing environments may need to re‑run initialization or apply updates to include new event data.
    • New Localization project referenced by the solution; consumers should restore/build the solution to pick it up.
    • Admin Panel resources and startup config changed; ensure appsettings.json is aligned.
  • How to test:

    • Build: dotnet build src/MUnique.OpenMU.sln
    • Run Admin Panel, verify language selector switches EN/ES and strings render correctly.
    • Verify summon self‑defense behavior (no unintended PK/self‑defense triggers with own summon).
    • Check event data presence (Rena drops, Golden Archer, White Wizard) after initialization.
    • Use log tail page to confirm live log streaming works during server activity.
  • Size and scope:

    • 217 files changed, 7,237 insertions, 608 deletions.
    • Touches: GameLogic, AdminPanel, Startup/Logging, Persistence/Initialization, Network packets, Docker, Docs, and Tests.

AdminPanel ES + presets Docker LAN/Public (RESOLVE_IP) y ajustes S6
eliminate 8080/8081
…nish-and-english

docs: add bilingual readme and fork changelog
…nish-and-english-q7sxr5

fix: apply custom drop to invasion boss
…anol

feat: add Spanish translations for server and panel messages
…se-payload

Send Chaos mix success rate and bonus to client
…sa-de-la-elfa

Add plugin for customizable summoned monsters and fix summond skill
…configurationplugin

refactor: remove plugin inheritance from summon config
…ping upstream FixItemRequirements2=61 and shifting fork-specific updates to 62-66; retain ElfSummonDefaults=250
…tem-for-translations

Localize remaining server interactions
fixing AI's nonsense
fixing AI's nonsense
fixing AI's nonsense part3
fix ui
@gemini-code-assist
Copy link

Summary of Changes

Hello @EmanuelCatania, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates significant improvements from a fork, focusing on enhancing the OpenMU server's usability, configurability, and stability. Key areas include comprehensive localization, a revamped Admin Panel with live log tailing, a refactored and more flexible summon system, and new event data for Rena, Golden Archer, and White Wizard. Additionally, it brings robust Docker configurations and refined logging mechanisms, making the server easier to deploy, manage, and debug.

Highlights

  • Localization: Introduced English and Spanish localization across the Admin Panel and server messages, with a new Localization project and dynamic language selection in the UI.
  • Admin Panel Enhancements: Added new pages for Craftings and Live Logs, improved tables, navigation, and UX across various .razor pages, and exposed a /api/logs/tail endpoint for log streaming.
  • Summon Logic Refactor: Refactored Elf summon behavior to allow configurable monster definitions and energy-based scaling via plugins, fixed self-defense interactions with own summons, and added detailed logging for summon behavior.
  • Gameplay & Event Updates: Implemented data and initialization for Rena global drops, Golden Archer, and White Wizard events, along with multiple fixes in crafting, inventory, trade, and NPC interactions.
  • Docker & Logging Improvements: Enhanced Docker setups with new compose variants for various deployment scenarios (LAN, public, Nginx integration), hardened Docker images with ICU support, and integrated in-memory log buffering for live log tailing.
  • Chat Command Extensions: Added new chat commands, including /itemstack for creating stacked or multiple items, and /startww to manually trigger the White Wizard invasion.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is a massive and impressive pull request that introduces significant improvements across the entire project. The addition of a localization system is a major step forward for internationalization, and the refactoring of the summon logic appears to be much more robust and feature-rich. The enhancements to logging, Docker setup, and the Admin Panel (especially log tailing) are also very valuable contributions. The code is generally of high quality. My review focuses on ensuring the new localization feature is used consistently and points out a couple of minor issues in documentation and code.

if (arguments.Count < requiredArgumentCount)
{
throw new ArgumentException($"The command needs {requiredArgumentCount} arguments and was given {arguments.Count}.", nameof(command));
throw new ArgumentException($"El comando requiere {requiredArgumentCount} argumentos y se recibieron {arguments.Count}.", nameof(command));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The exception message here is hardcoded in Spanish. Exception messages in core utility functions like this should generally be in English for consistency in logging and debugging across different development environments. Hardcoding a specific language can make it difficult for developers who don't speak that language to understand errors.

            throw new ArgumentException($"The command needs {requiredArgumentCount} arguments and was given {arguments.Count}.", nameof(command));

foreach (var requiredProperty in requiredProperties)
{
stringBuilder.AppendLine($"The required argument named {requiredProperty.Name} was not used.");
stringBuilder.AppendLine($"El argumento obligatorio '{requiredProperty.Name}' no fue especificado.");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This exception message is hardcoded in Spanish. For consistency and easier debugging for a global audience, it's better to keep exception messages in core utilities in English.

            stringBuilder.AppendLine($"The required argument named '{requiredProperty.Name}' was not used.");

catch
{
throw new ArgumentException($"The argument {propertyInfo.Name} was given a invalid type, it expects the value to be of the type {propertyInfo.PropertyType.Name}.");
throw new ArgumentException($"El argumento {propertyInfo.Name} tiene un tipo inválido, se esperaba {propertyInfo.PropertyType.Name}.");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This exception message is hardcoded in Spanish. It's recommended to use English for exception messages in shared utility code to ensure they are understandable by all developers.

            throw new ArgumentException($"The argument {propertyInfo.Name} was given an invalid type; it expects the value to be of type {propertyInfo.PropertyType.Name}.");

@@ -0,0 +1,314 @@
# OpenMU Project / Proyecto OpenMU

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This backup file (.bak) appears to have been committed by accident. Such files should not be part of the version control history. Please remove it from the pull request.

Comment on lines +199 to +210
### Deploy from a remote fork (compose overlay)

- Overlays in `deploy/all-in-one` allow building the image directly from your fork using a remote git context.
- Required env var: `OPENMU_FORK_CONTEXT` in the form `https://github.com/<user>/OpenMU-<fork>.git#<branch>:src`.
- Example commands (server):
- `export OPENMU_FORK_CONTEXT="https://github.com/EmanuelCatania/OpenMU-S2.git#master:src"`
- `docker compose -f docker-compose.no-nginx.yml -f docker-compose.override.yml -f docker-compose.public-dns.yml -f docker-compose.npm-net.yml -f docker-compose.from-fork.yml build --no-cache --progress=plain --build-arg APP_UID=1000 openmu-startup`
- `docker compose -f docker-compose.no-nginx.yml -f docker-compose.public-dns.yml -f docker-compose.npm-net.yml -f docker-compose.from-fork.yml up -d --no-deps --force-recreate openmu-startup`

Notes
- `src/Startup/Dockerfile` installs ICU (`icu-libs`, `icu-data-full`) and sets `DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false` to enable real cultures on Alpine.
- If you are behind a proxy (NPM/Cloudflare), enable WebSockets for `/_blazor` and avoid orange cloud (DNS only) for the host.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This section, "Deploy from a remote fork (compose overlay)", is a duplicate of the one starting at line 162. Please remove one of them to keep the documentation clean and avoid confusion.

Comment on lines +23 to +27
await this.SendMessageToPlayerAsync(sender, $"Chat bloqueado: quedan {(int)Math.Ceiling(remainingChatBan.TotalMinutes)} minuto(s).", MessageType.BlueNormal).ConfigureAwait(false);
}
else
{
await this.SendMessageToPlayerAsync(sender, $"Chat Ban: {(int)Math.Ceiling(remainingChatBan.TotalSeconds)} second(s) remaining.", MessageType.BlueNormal).ConfigureAwait(false);
await this.SendMessageToPlayerAsync(sender, $"Chat bloqueado: quedan {(int)Math.Ceiling(remainingChatBan.TotalSeconds)} segundo(s).", MessageType.BlueNormal).ConfigureAwait(false);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

These chat ban messages are hardcoded in Spanish. To maintain consistency with the new localization feature, please use the player.GetLocalizedMessage helper to make these strings translatable.

Comment on lines +26 to +45
await this.SendMessageToPlayerAsync(player, "No es posible formar party durante este evento.", MessageType.BlueNormal).ConfigureAwait(false);
return;
}

if (toRequest.Party != null || toRequest.LastPartyRequester != null)
{
await this.SendMessageToPlayerAsync(player, $"{toRequest.Name} is already in a party.", MessageType.BlueNormal).ConfigureAwait(false);
await this.SendMessageToPlayerAsync(player, $"{toRequest.Name} ya está en un party.", MessageType.BlueNormal).ConfigureAwait(false);
return;
}

if (isPartyMember)
{
await this.SendMessageToPlayerAsync(player, "You are not the Party Master.", MessageType.BlueNormal).ConfigureAwait(false);
await this.SendMessageToPlayerAsync(player, "No eres el líder del party.", MessageType.BlueNormal).ConfigureAwait(false);
return;
}

if (await toRequest.PlayerState.TryAdvanceToAsync(PlayerState.PartyRequest).ConfigureAwait(false))
{
await this.SendPartyRequestAsync(toRequest, player).ConfigureAwait(false);
await this.SendMessageToPlayerAsync(player, $"Requested {toRequest.Name} for Party.", MessageType.BlueNormal).ConfigureAwait(false);
await this.SendMessageToPlayerAsync(player, $"Has enviado una solicitud de party a {toRequest.Name}.", MessageType.BlueNormal).ConfigureAwait(false);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The messages in this method are hardcoded in Spanish. Please use the new localization system (player.GetLocalizedMessage(...)) to make them translatable and consistent with the rest of the application.

Comment on lines +108 to 116
var message = $"Se inicia defensa propia por el ataque de {attacker.Name} a {defender.Name}!";
await defender.InvokeViewPlugInAsync<IShowMessagePlugIn>(p => p.ShowMessageAsync(message, MessageType.BlueNormal)).ConfigureAwait(false);
await attacker.InvokeViewPlugInAsync<IShowMessagePlugIn>(p => p.ShowMessageAsync(message, MessageType.BlueNormal)).ConfigureAwait(false);
}

private async ValueTask EndSelfDefenseAsync(Player attacker, Player defender)
{
var message = $"Self defense of {defender.Name} against {attacker.Name} diminishes.";
var message = $"La defensa propia de {defender.Name} contra {attacker.Name} finaliza.";
await defender.InvokeViewPlugInAsync<IShowMessagePlugIn>(p => p.ShowMessageAsync(message, MessageType.BlueNormal)).ConfigureAwait(false);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The self-defense messages are hardcoded in Spanish. Please use the new localization service to make them translatable.

}

await player.GameContext.SendGlobalMessageAsync($"{selectedCharacter.Name} entered the game.", MessageType.BlueNormal).ConfigureAwait(false);
await player.GameContext.SendGlobalMessageAsync($"{selectedCharacter.Name} entró al juego.", MessageType.BlueNormal).ConfigureAwait(false);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This global message is hardcoded in Spanish. Please use the localization service to allow for translation.

        var message = player.GameServerContext.Localization.GetString("Server_Message_PlayerEnteredGame", selectedCharacter.Name);
        await player.GameContext.SendGlobalMessageAsync(message, MessageType.BlueNormal).ConfigureAwait(false);

this._classNumber = classNumber;
this._minimumLevel = minimumLevel;
this._warningMessage = $"Couldn't unlock {className}, because it couldn't be found in the configuration.";
this._warningMessage = $"No se pudo desbloquear {className}, porque no se encontró en la configuración.";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This warning message is hardcoded in Spanish. It should be in English by default or use the localization system, especially since it's part of a base class.

        this._warningMessage = $"Couldn't unlock {className}, because it couldn't be found in the configuration.";

@sven-n
Copy link
Member

sven-n commented Oct 16, 2025

Thanks for this contribution. Because it's so big I'll need some time to review it. I'll probably need to divide it into several smaller PRs, like one per feature. Just leave this PR open, so I can keep track of which files I already reviewed.
However, I can't merge the translations yet, as this project is in english. To support more languages I'll first have to move all localizable strings to resources.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants