Giter Site home page Giter Site logo

munique / openmu Goto Github PK

View Code? Open in Web Editor NEW
640.0 67.0 264.0 63.31 MB

This project aims to create an easy to use, extendable and customizable server for a MMORPG called "MU Online".

Home Page: https://munique.net

License: MIT License

C# 94.16% JavaScript 0.01% CSS 3.83% TypeScript 0.17% HTML 1.01% Dockerfile 0.04% XSLT 0.68% Shell 0.01% SCSS 0.08% PowerShell 0.01%
mmorpg mmorpg-server muonline mu server-emulator mu-online games hacktoberfest

openmu's Introduction

OpenMU Project

License Codacy Badge Gitter chat Discord chat

Platform Build Status
Windows Windows Build Status
Linux (Docker) Docker Build Status
NuGet Packages
MUnique.OpenMU.Network NuGet Badge
MUnique.OpenMU.Network.Packets NuGet Badge

This project aims to create an easy to use, extendable and customizable server for a MMORPG called "MU Online". The server supports multiple versions of the game, but the main focus is version of Season 6 Episode 3 using the ENG (english) protocol. However, parts of the software can also be suitable for the development of other games, even for other kind of games.

The code is a complete rewrite from scratch - it's not based on pre-existing projects, and it's also explicitly not based on decompiled server sources or their countless derivates.

There also exists a blog which may contain some valuable information about this development.

Current project state

This project is currently under development without any release. You can try the current state by using the available docker image, also mentioned in the quick start guide.

Licensing

This project is released under the MIT license (see LICENSE file).

Used technologies

The project is mainly written in C# and targets .NET 8.0.

The servers admin panel is hosted on an embedded ASP.NET Core webserver (Kestrel) and implemented as Blazor Server App.

At the moment the persistence layer uses the Entity Framework Core and PostgreSQL as database. Additionally, it's also possible to start it in a non-persistent in-memory mode.

The project supports distributed hosting based on Dapr. Alternatively, it can be hosted in one process as well.

Deployment

We provide Docker images and docker-compose files for easy deployment. Please take a look at the deploy-folder of this project.

Contributions

Contributions are welcome if they meet the following criteria:

  • Language is english.

  • Code should be StyleCop compliant - this project uses the StyleCop.Analyzers for VS2022 so you should see issues directly as warnings.

  • Coding style (naming, etc.) and quality should fit to the current state.

  • No code copied/converted from the well-known decompiled source of the original server.

If you want to contribute, please create a new issue for the feature or bug (if the issue doesn't exist yet) so we can see who is working on something and can discuss possible solutions. If it's a small thing, you can also just send a pull request without adding an issue.

Apart of that, contributions from non-developers are welcome as well. You can test the server, submit issues or suggestions, packet descriptions or documentations about the concepts and mechanics of the game itself. Please use markdown files/syntax for this purpose.

If you have questions about that, don't hesitate to ask in our discord channel or by submitting an issue.

How to contribute code

If you want to contribute code, please do the following steps:

  1. fork this project from the original MUnique OpenMU Project.
  2. create a feature branch from the master branch
  3. commit your changes to your feature branch
  4. submit a pull request to the original master branch
  5. lean back, wait for the code review and merge :)

How to use

Please have a look at the quick start guide.

Gameplay differences to the original server

This project doesn't have the goal to copy the original MU Online server behavior to 100 %. This is not entirely possible, because the original server is written in another programming language and has a completely different architecture. With some points we make our life easier in this project, with other points we try to improve the gameplay.

Calculations

The calculations of attribute values (like character damage decrement etc.) are done with 32 bit float numbers and without rounding off, like the original server does at some places. E.g. distributed stat points always have effect, while in the original server effects might get rounded down. For example, when 4 points of strength gives 1 base damage, the original server doesn't calculate a fraction of 1 damage for 3 points, while OpenMU calculates 0.75 damage. This damage has then an effect in further calculations.

Countdown when changing character or sub-server

The original server uses a five second countdown when a player wants to change his character or the sub-server. Maybe this was done for some performance reasons, as the original server would then save the character/account data. We think that's really annoying and see no real value in that, so we don't use a countdown.

openmu's People

Contributors

addrange avatar afrokick avatar and3rsl avatar antonioanerao avatar dependabot[bot] avatar guser9822 avatar halflumi avatar hoangdangtrungvn avatar icheat2win avatar ja0n avatar jasondavindev avatar jhonynet avatar juliancasaburi avatar leandrorlls avatar marcosdenoni avatar marcusviniciusss avatar mariogk avatar mosch0512 avatar muonlinedev avatar najoast avatar nmarazov avatar radzki avatar recone83 avatar riicksouzaa avatar sven-n avatar terry83299387 avatar thismushroom avatar tocher avatar wojciech-dabrowski avatar wplatform avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

openmu's Issues

client-server CheckSum

Hi, i'v emulate client login and select character, then join into world and in some seconds get disconnect from server.
i start investigate and see this packets:
c3 08 03 00 5b cf d2 11
c3 08 03 00 30 31 1f ae
maybe this is checksum? do you know how to get this/create?
this code capture checksum and return to client?

also next packet after is:
c1 05 18 16 5f
and it's always the same

thanks.

Sending Letters is not working - LetterBody missing in entity model

[ERROR] 2018-03-02 12:44:15,810 [MUnique.OpenMU.GameServer.RemoteView.RemotePlayer] [1] - System.InvalidOperationException: The entity type 'LetterBody' was not found. Ensure that the entity type has been added to the model.
bei Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.GetOrCreateEntry(Object entity)
bei Microsoft.EntityFrameworkCore.DbContext.EntryWithoutDetectChanges[TEntity](TEntity entity)
bei Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)
bei MUnique.OpenMU.Persistence.EntityFramework.RepositoryManager.CreateNew[T](Object[] args) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\Persistence\EntityFramework\RepositoryManager.cs:Zeile 186.
bei MUnique.OpenMU.GameLogic.PlayerActions.Messenger.LetterSendAction.CreateLetter(Player player, String receiver, String message, String title, Byte rotation, Byte animation) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameLogic\PlayerActions\Messenger\LetterSendAction.cs:Zeile 108.
bei MUnique.OpenMU.GameLogic.PlayerActions.Messenger.LetterSendAction.SendLetter(Player player, String receiver, String message, String title, Byte rotation, Byte animation) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameLogic\PlayerActions\Messenger\LetterSendAction.cs:Zeile 86.
bei MUnique.OpenMU.GameServer.MessageHandler.LetterSendHandler.HandlePacket(Player player, Byte[] packet) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameServer\MessageHandler\LetterSendHandler.cs:Zeile 46.
bei MUnique.OpenMU.GameServer.ConfigurablePacketHandler.HandlePacket(Player player, Byte[] packet) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameServer\ConfigurablePacketHandler.cs:Zeile 56.
bei MUnique.OpenMU.GameServer.RemoteView.RemotePlayer.PacketReceived(Byte[] buffer) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameServer\RemoteView\RemotePlayer.cs:Zeile 72.

3rd class characters are shown with 0 health, mana etc.

How to reproduce:

  • Initialize the database (or start in demo mode)
  • Enter the game with test400/test400
  • Maximum Health, Mana, AG, Shield is 0

Possible solution:
For 3rd class characters, it might be required to send an additional packet/message, which also contains the master level etc. Packet type would be 0xF3 0x50.

Skype?

Tremendous work!, do you have skype or some other instant messaging? I got couple of questions regarding protocol handling.

Pet system (Raven, Dark Horse) is missing

Ideas:

  • Pet level could be item level
  • ItemDefinition gets something like a PetDefinition (%exp of character, maximum level, behavior-modes and maybe their corresponding class names)

Tasks:

  • Implement pet leveling and pet info request/response
  • Implement raven attacks

[Features] JSON configurations

As a client side, I want to have JSON file with all configurations for items, characters and etc.

It would be perfect to use server side DataModel's project in client side application.

Porting to modern C++?

I'm thinking about setting up a tiny playground server on my orangepi and I'm curious if you'd be interested in porting your sources to modern C++ since it's more portable, features safe mem allocation and most of other stuff which make people use C#. I'd of course help with such process. If not, is there any reason I'm not seeing to use C# beside just a matter of preference?

Another added bonus is independence from Visual Studio - one could just use clang/gcc and build it with single make command without bloating HDD with another IDE.

I was with muo since 2k5 until about 2012 doing minor dev and I have periodically some thoughts about returning to this game. I'm glad that there are some open movements in development these days - you're doing amazing work!

Does the server work on Linux?

Would be interesting if it would run correctly on Linux. Current mono supports .net 4.7, so it should work. Compiling also works as Travis CI is actually running on Linux.
To take this further, it would be nice to know if it would run on ARM servers (e.g. scaleway), too.

Starting the game server takes too long

After extending some game map initialization data where I added NPCs and Monsters and their spawn points with 792148e, the startup time has gone up from around 15 seconds to over a minute. This is caused by loading the GameConfiguration which includes all this data.
I think when adding the rest of the data to the configuration it could take several minutes to load the GameConfiguration - not acceptable.

Maybe it's time to investigate how to integrate a document database (or a similar approach), where we have the GameConfiguration in just one document.

Can't set item price of personal store

When trying to set the price of an item of the personal store, it ends with an exception:

System.IndexOutOfRangeException: Der Index war außerhalb des Arraybereichs.
bei MUnique.OpenMU.GameLogic.PlayerActions.PlayerStore.SetItemPriceAction.SetPrice(Player player, Int32 slot, UInt32 price) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameLogic\PlayerActions\PlayerStore\SetItemPriceAction.cs:Zeile 20.
bei MUnique.OpenMU.GameServer.MessageHandler.StoreHandler.ReadItemPrice(Player player, Byte[] buffer) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameServer\MessageHandler\StoreHandler.cs:Zeile 132.
bei MUnique.OpenMU.GameServer.MessageHandler.StoreHandler.HandlePacket(Player player, Byte[] packet) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameServer\MessageHandler\StoreHandler.cs:Zeile 52.
bei MUnique.OpenMU.GameServer.ConfigurablePacketHandler.HandlePacket(Player player, Byte[] packet) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameServer\ConfigurablePacketHandler.cs:Zeile 56.
bei MUnique.OpenMU.GameServer.RemoteView.RemotePlayer.PacketReceived(Byte[] buffer) in D:\Benutzer\Sven\Documents\GitHub\OpenMU\src\GameServer\RemoteView\RemotePlayer.cs:Zeile 72.

The reason is, that it's somehow subtracting too much from the item slot sent by the data packet here:

int itemSlotInStore = buffer[4] - InventoryConstants.FirstStoreItemSlotIndex;

[OSX, VS4MAC] Admin panel not working

Hi

I had an issue with admin panel.

When I open a tab with localhost:1234/admin, some errors occurred in console:

GET http://localhost:1234/content/js/app.js 404 (Not Found) admin:14 GET http://localhost:1234/content/css/app.css 404 (Not Found)

How can I run minifier that creates app.js and app.css?

VS2017, OSX 10.13.6

Replace fluxxor in AdminPanel

The AdminPanel currently uses fluxxor as React Flux implementation. This has several downsides:

  • It doesn't seem to be maintained anymore
  • Using ES6 classes is not possible, because fluxxor uses Mixins

As there are now better alternatives, we should switch to something else, e.g. Redux.

Moving to other maps by using the warp list

Currently, moving to other maps by using the warp list is not working.
I seemed to have the assumption that the involved packets changed from season 5 to 6 when I look at the responsible classes:
WarpS54Action
WarpS54Handler

I guess because of this assumption the data of the warp list (GameConfiguration.WarpList) is not getting initialized yet.
As I found out, this packets are still being used and filling the data would make warping possible again.
Unfortunately WarpInfo is not included in the entity framework yet, and the property GameConfiguration.WarpList is a Dictionary which makes it a bit harder to map. However, making it virtual and running the T4 templates should do the trick.

Move data initialization (seeding) out of the EF-Core migrations

Currently, the first migration after creating the initial model on the database is inserting all the initial data. The problem is, this happens already with the most current model which is not yet existing on the database. So for example, when a later migration adds a new column and this column is used by the initial data insertion code, it would fail.
See also 76b13dc.

The solution could be to remove this Seed-Migration and only run the data initialization after all migrations if the database didn't exist before at MUnique.OpenMU.Persistence.EntityFramework.RepositoryManager.ApplyAllPendingUpdates().

Implement a Quest System

Current state

MU Online itself has two different quest systems (Class Changes etc. and Elf Soldier quests). It would be great if we could implement them in a generalized way. Only the view should decide which data packets are sent to the client.

Documentation

I documented the messages for the older quest system (C1A0 to C1A4) already. It's used for the character class evolution and the combo skill.

The elf soldier provides another quest system. It uses different messages (C1F6) and usual quests are built to kill x monsters to get experience or items as reward. I documented these messages as well.

Quest state as attribute value

Some skills require that certain quests have been completed, e.g. Crystal of Destruction requires that the "Marlon Quest" is done. Usually the client checks these quest states itself. To prevent cheating, the server has to do this, as well.

Idea:

  • Quest state as Attribute Value of a Character
  • Quest state as Attribute Requirement (Skill.Requirements)

A quest definition could define if the completed quest should add an attribute value to the character.
These attribute values could also be used further, for example as requirement for maps or to wear items.

Client interaction

The player view has to be extended to be able to send the quest state(s). As I wrote above, there should be a generalized view interface for quests.
The view implementation can then decide which messages (depending on the quest system) should be sent to the client. Ideally, the game logic should make no difference about the different quest systems.

Tasks

  • Old Quest System (Level 150, 220, ...)
  • New Quest System
    • Message structs, plugins
    • Logic
    • Initialization data
    • Testing
  • Quest completion states as attribute requirements for some skills

Attribute Requirements for GameMaps

Some maps have "special" requirements, which a Character has to fulfill until it can enter or even stay at it.

Examples

Icarus

Requires that a Character wears a Wing, Cape or a Dinorant.
Idea:

  • Add a attribute "CanFly" with a value of 1 to all wings, capes and dinorant at their ItemDefinition.BasePowerUpAttributes.
  • Add a requirement to Icarus, where "CanFly" needs to be at least 1.

Kanuru Event Map

Requires that a Character wears a "Moonstone Pendant".
Idea:

  • Add a attribute "MoonstonePendantEquipped" with a value of 1 to the ItemDefinition.BasePowerUpAttributes of the Moonstone Pendant.
  • Add a requirement to the event map, where "MoonstonePendantEquipped" needs to be at least 1.

Required extensions

  • GameMapDefinition needs a collection of AttributeRequirements
  • The GameLogic needs to be extended so that the requirements are checked before entering the map and when equipped items are changed

What else can we do with that?

Well, this leaves much room for customization. There could be "VIP" maps, which could require certain attributes. Not just for paying customers, but possibly also game masters. Another idea could be event maps which require that players equip a certain item, e.g. a race track map which require to wear a Unicorn.

doc/packets about LoggedIn

in docs very good write about character select/start/etc, can you add about LoggedIn, which packet type, code/subcode and how to send login/pass to server.
thx

Can't equip any item anymore

Even if a character matches the requirements, it can't equip an item.
After some debugging, I saw that the ItemSlots of an ItemSlotType are empty (itemDefinition.ItemSlot.ItemSlots).
That's probably caused by my recent change for #10 to load the complete configuration as json - these slot values are saved as a comma-separated string on the database. This might require some special handling.

Building under Linux

The goal is to be able to build and run it on Linux right after cloning the repository.

To build AdminPanel under Linux, you have to use msbuild - it's not possible to pass the OutputPath to the other targets with xbuild - a bug?
Then TransformBabel needs a windows-independent JS-Engine (VroomJs), however I didn't get it to work. The documentation for React.NET on Linux is flawed, as it depends on a SVN repository which is not available anymore.
CopyScripts works - except the bundling of CSS/JS. The new msbuild somehow behaves differently and stops building :-( Maybe a bundling tool can be used here, instead.

Rule engine for item price calculation

Current state

The item price calculation is pretty complicated with a lot of special logic - it‘s leaned on the original price calculation function. However, the code knows too much about the data - it should not know item numbers at all. It’s impossible to add a new item which requires special logics without touching the code.

Goal

Pricing rules defined by data, referenced by the ItemDefinition. The calculation just works on these rules, without special logics which handles specific item numbers. Ideally, new items should never require code extensions.

How

There could be different kind of pricing rules, e.g.:

  • Fixed price (e.g. Jewels)
  • Fixed price defined for each item level (e.g. Blood Bones)
  • Automatic (e.g. Armor), which applies multiple rules for different kinds of options

Implement Event Maps

Currently no event maps are implemented. Event maps include for example 'Blood Castle' and 'Devil Square'.
Different from the original game we could also change that some of these events do not run in an interval (like once every hour), but every player/party can instantly enter the map whenever they want. They could get an exclusive instance of it, so there are no other parties disturbing. Of course, this can't be done with Player-versus-Player events like 'Chaos Castle'.

  • Devil Square
  • Blood Castle
  • Chaos Castle
  • Illusion Temple
  • Double Goer

Decoupling ChatServer from DataModel

Currently the ChatServer project indirectly depends on the DataModel.
The dependency can be shown as follows:
ChatServer -> Interfaces -> DataModel

The Interface project just uses the following stuff of the DataModel:
FriendViewItem -> can be moved to the Interfaces project
LetterHeader -> can be moved to the Interfaces project
Guild, GuildMemberInfo, GuildPosition -> ???

[Error] ItemDefinition -> Skill

Error Overview:

  1. Add any of learnable items to the npc store
  2. Purchase learnable item
  3. Try to use it

Result:

[ERROR] {date-time} [MUnique.OpenMU.GameServer.RemoteView.RemotePlayer] [0] - System.NullReferenceException: zero pointer exception. _(translated from russian)_
in MUnique.OpenMU.GameLogic.PlayerActions.ItemConsumeActions.LearnablesConsumeHandler.ConsumeItem(Player player, Byte itemSlot, Byte targetSlot)
in MUnique.OpenMU.GameLogic.PlayerActions.ItemConsumeActions.ItemConsumeAction.HandleConsumeRequest(Player player, Byte inventorySlot, Byte targetSlot)
in MUnique.OpenMU.GameServer.MessageHandler.Items.ConsumeItemHandler.HandlePacket(Player player, Byte[] packet)
in MUnique.OpenMU.GameServer.ConfingurablePacketHandler.HandlePacket(Player player, Byte[] packet)
in MUnique.OpenMU.GameServer.RemoteView.RemotePlayer.PacketReceived(Byte[] buffer)

Observation 01

After shortlook on the error one can figure out that exception traces back to:
MUnique.OpenMU.GameLogic.PlayerActions.ItemConsumeActions.LearnablesConsumeHandler.ConsumeItem(Player player, byte itemSlot, byte targetSlot)

if (player.SkillList.ContainsSkill(learnable.Skill.SkillID.ToUnsigned()))
{
...
}

because of NULL value at learnable.Skill

After I've looked at
MUnique.OpenMU.GameLogic.PlayerActions.Items.BuyNpcItemAction.BuyItem(Player player, byte slot)

And observed that storeItem also has NULL at storeItem.Definition.Skill
Therefore all items stored in npcStore has no Skill

Observation 02

Whenever one take a look at
MUnique.OpenMU.Presistence.EnityFramework.ExtendedTypes.ItemDefinition
we can observe that Guid? SkillId defines correctly and there is such Id in Skill table, but RawSkill remains NULL therefore Skill would be NULL since it is copied from RawSkill

Observation 03

  1. Buy learnable item from npc store
  2. Reboot server
  3. Login and try to use learnable item from inventory
  4. Awesome it is working with no error.

Plugin System

To make the server extensible without touching the source code of the core logics and also to make some existing logics configurable, we could implement a plugin system. I would like to describe my idea of such a system.

Plugin Points

A plugin point is something which collects all plugins of one defined plugin type.
We have to define several points where we execute all plugins of a defined plugin types of a point.
For some events we could actually define two points - one before with cancel flag, another one after some event happened.

Suggested Plugin Points

  • Chat/Whisper Message received

  • Chat Command received

  • Character created

  • Character deleted

  • Player.PlayerState changed, example cases:

    • Player Entered Game
    • Player Left Game
    • Before saving player data
    • Player Authenticated
    • Trade finished
  • Object Added To Map

    • Includes: Player Entered Map, Item Dropped, Monster added
  • Object Removed From Map

  • Attribute Value Calculation

  • Attribute Value Changed

    • Includes: Level up, Stat Attribute increased, etc.
  • Object got killed

  • Object got hit

  • Object moved

  • Player talked to NPC

  • Item consuming/consume/consumed

  • Item sold to NPC

  • Item sold to other player through personal store

  • Item moving/moved

  • Item created

  • Item destroyed

  • Data initialization plugins

  • Network related plugin points:

    • Before Send (Apply Encryption, Logging)
    • Before Handle Received Messages (Apply Decryption, Logging)
    • PacketHandler plugin

Plugin Types

Then we have to define interfaces for these plugin types. Some may have additional event arguments, but most will just need the Player object.

Usage?

It would make sense to have access to the plugin points through the GameContext. Example:

// we're in the CharacterCreateAction and want to call its plugin point, after the character got created:
player.Context.InvokePlugInPoint<ICharacterCreatedPlugIn>(plugIn => plugIn.DoSomething(player, character)); // InvokePlugInPoint iterates through all active plugins.

This is a more open implementation, since the code has direct access to the plugins. This could be hidden, but would be more complex to implement.

PlugIn Registration and Configuration

Another point is the registration and configuration of plugins. My idea is:

  • Automatically collecting all available plugins by reflection at the start of the server
  • We need a configuration for each plugin (active-flag, order of execution, etc.)
    • If a new external plugin was added (no configuration exists), it should be inactive by default to prevent malicious plugins to be executed
    • We save this configuration in the database. Configuration could take place over the admin panel interface.
    • External plugins / assemblies:
      • How to include?
        • By adding a configuration for it?
          • We could save external plugin assemblies in the database within their configuration
          • Bonus: Wouldn't it be nice to have an editor in the admin panel, so we could develop and deploy plugins on-the-fly without restarting the server?
        • By dumping an external assembly into a "plugins" folder?
      • How to keep them compatible after an update?
  • To group plugins by feature we could have a FeaturePlugIn which holds all plugins of a feature together. If a plugin belongs to a feature, its active-flag should also depend on the active-flag of the feature.

Move existing logic to plugins

As a last step, we could move some existing logic to plugins. Of course, core logic should be left alone.
Some ideas:

  • generating item drops when monster got killed.
  • adding experience to the player(s) when a monster got killed
  • drop item from player when it died
  • talking to NPCs
  • item consume. There are already handlers which are defined in the ItemDefinition. Maybe this could be defined the other way around: A plugin could decide if it can handle the requested consumption of an item.

[Error] Monster walking behaviour

Overview:

  1. Add new SpawnArea with any kind of monster (e.g. Giants (Lorencia))
  2. Make SpawnArea as a single cell spot (x1 == x1 && y1 == y2)
  3. Make SpawnArea spawning 20 monsters
  4. Reinit database for spawn area initialization
  5. Walk to the spawn area
  6. Observe empty spot

Observation:

  1. Monsters are walking towards 0,0 coordinates of the map.
  2. Some monsters remain standing/walking around the spot area.
  3. For DirectHit spell system monsters that remain standing/walking are acting correctly when being hit.
    3.1) If you want to hit them with DirectHit spell - hit them - they will die, you will get exp/zen. No drop.
  4. For AreaHit spell system those monsters that remain standing/walking are invisible.
    4.1) If you want to hit them with AreaHit spell - try to - the will act like being hit but no damage would be done. Therefore as we can see from debugging - system doesn't detect monsters around you in the specified skill range.

Ideas:

  1. Yup, monsters are walking thats obvious. - Need to implement correct work of walk range (like the definition of how far they can move from initial spawn area (for the single cell spawns) and new Point distance (for area spot that is bigger then walk range). Moreover implement logic to prevent monsters from leaving the SpawnArea.

2(+ 3-4)) Didn't debug it well yet, just shortlooked. But first ideas and observations were:

  • If you take Evil Spirits and start casting somewhere in the corner of the map near 0,0 (as close as you can) - you will hit those monsters (but you cannot see them). Why do I think they stand at 0,0 - because of EXP trail from monster to caster after being killed (not alway working) + you get exp and zen.
  • It may be problem with server-client sync and maybe somehow bucket system bug.
    When on server side monsters walked to 0,0 but on client side they are displayed on other places. (take a look at the map in the admin panel - all monsters are on correct places but ingame - they are not).
    Why we can hit them with DirectHit spells - because client send the data about monster and it is ok to calculate hit.
    Why we cannot hit them with AreaHit spell - because non-target spell use being sent to the server and the server should determine monsters being hit int the spell range around the caster.

PS. I would investigate it deeper this eve and add comments about to make it more detailed.

When an item can't be moved, send proper response

Currently, when an item can't be moved to the requested item slot of the inventory, the client gets no response and gets stuck - item stays at the mouse cursor and can't be dropped/moved somewhere else.
E.g. when trying to equip an item, it just says "You can't wear this item" and that's it.

Resource manager for texts

I've noticed that you use raw text messages directly in code, e.g.

player.PlayerView.ShowMessage("Your account has been temporarily banned by a game master.", MessageType.BlueNormal);

However, this leads to problems with translating text game server for non-English regions. Therefore I suggest to introduce an enitity which would provided text for given ID on run-time, possibly from disk.

Implement Launcher with auto-update feature

There is already a client launcher project which is pretty basic.
It's missing a dialog to configure the game client (resultion, sound etc.) and the auto-update feature.

We could implement auto-update compatible to the original launcher, and/or make our own (e.g. with torrents).

Refactor Data Model - Master Skill Definitions

What's the problem?

It seems like the current data model for master skills is too complicated. It was built under the assumption that the same skill can be a master skill at a different rank for different character classes. This was the case in previous seasons when I probably wrote the code. However, now that's not required anymore, so we can simplify things. I verified this by running a simple tool which compares all data of the same skill ids. As a source I used this file. As you can see there, there are common master skills for all characters. When you have a look at the master tree in-game, it's the left tree which is the same for every character. All other skills which are reused (e.g. Duel Master uses skills of knights and wizards), have the same rank and values.

As a side note, Webzen changed how master skills are defined in the newer seasons, too. Back then, when the master skills were introduced, every level of a master skill was defined as a separate Skill with its own ID. In Season 6, all levels of a master skill are defined under one Skill.

So, what can be simplified?

  • A Skill doesn't need a collection of MasterSkillDefinitions. One reference to a MasterSkillDefinition is enough.
  • MasterSkillDefinition doesn't need the property for the required CharacterClass anymore, the skill itself already defines which characters are allowed to learn or use it.
  • Therefore, we don't need different MasterSkillRoots per CharacterClass, too. Three common roots for all classes are enough.
  • This simplifies the code which use the changed/removed properties - unit tests, too.

Special case

Disclaimer: The solution for this special case is explicitly not a required part for the solution of this issue. I just want to write my thoughts about it, so that it's not forgotten.

There seems to be one skill which is different to all other skills. The "Triple Shot Mastery" requires all 10 of 10 possible master points to be allocated until it has effect. To understand my idea, I need to explain how the triple shot skill works. Currently it's not yet explicitly implemented, but handled by the common skill hit handler for skills of type SkillType.AreaSkillExplicitHits. Skills of this type send an animation packet (with a counter) and separate hit packets (also with the corresponding counter value of the animation packet). The check for the counter value is currently not yet implemented, so it's currently vulnerable to cheating. To check that there happens no cheating, we need to implement an explicit area skill hit packet handler for this particular skill (and probably for other skills as well, that's why it's way out of scope of this issue).
I see two ways to implement it here:

a) It could be implemented by adding a BaseAttributeValue with an attribute like "Triple Skill Number of Arrows" for all Elfs classes, with an initial value of 3. Each master level of the master skill adds a value of 0.1 (by Skill.PassivePowerUps). So it will reach the value of 4 not until level 10 is reached.

b) The handling code could assume an initial value of 3, and the master skill could could add a value of 0.1 (by Skill.PassivePowerUps) to an attribute like "Additional Number of Triple Skill Arrows".
Regardless of the actual way, the code can then check if the received hits of one animation exceed the number of allowed arrows.

Items can't change their owner - Exceptions at Trade and Item Drop

See also #7. Later, with c653d4b the property of Item.ItemStorage has been removed. It seemed that this property wasn't needed and it fixed an issue - however, it causes other issues, too. With in-memory persistence it works, but with entity framework core it doesn't.

The item doesn't know its owner (ItemStorage) anymore, this is only known to the entity framework context as shadow property. During the trade (or item drop), the item gets detached from the originating context and attached to another context. At trade, it's the trade context, where all traded items will are added. So, what happens if you save this trade context? Probably not much, just a changed item slot will be saved. The item storage isn't updated.

Ideas: We add Item.ItemStorage again. To fix the issues which c653d4b tried to solve, we could do the following.
When trading, we set a "dummy" of the item storage which just holds the id of the originating ItemStorage, without filled Items. Before committing, we set the dummy of the target item storage, so that it's getting updated. Alternatively, we can define to Ignore the ItemStorage.Items for the TradeContext.

Database Context issues when Items change their owner

Currently it's not taken care of Items which are changing their owner. This can happen by several ways:

  • Item dropped
    • Item will disappear after some time -> Item will be saved by dropping player context
    • Item will be picked up by another player -> Exception at next save point
  • Item is traded -> Exception at next save point

[Error] Gates issue

Steps to reproduce:

  1. Go to the Lorencia -> Devias gate
  2. Enter Devias
  3. Go back to Lorencia

Result:

No error occure but server and client stuck.
Short look: stuck occures at the moment when

 public void EnterGate(Player player, EnterGate enterGate){
...
if (player.CurrentMap.Definition.EnterGates.Contains(enterGate) && !(player.X >= enterGate.X1 - INACCURACY &&
                  player.X <= enterGate.X2 + INACCURACY &&
                  player.Y >= enterGate.Y1 - INACCURACY &&
                  player.Y <= enterGate.Y2 + INACCURACY))
            {
                return;
            }
...
}

causes return. Return triggers in 90% of cases due to small INACCURACY (currently its 2). Tested with 4 - everything is fine.

After INACCURACY changed to 4 and it become working next error occured:

[ERROR] 2018-07-14 15:18:37,227 [MUnique.OpenMU.GameServer.RemoteView.RemotePlayer] [0] - System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта.
   в MUnique.OpenMU.GameLogic.Player.WarpTo(ExitGate gate) в D:\MuProject\TheServer\OpenMU-1\src\GameLogic\Player.cs:строка 502
   в MUnique.OpenMU.GameLogic.PlayerActions.WarpGateAction.EnterGate(Player player, EnterGate enterGate) в D:\MuProject\TheServer\OpenMU-1\src\GameLogic\PlayerActions\WarpGateAction.cs:строка 55
   в MUnique.OpenMU.GameServer.MessageHandler.WarpGateHandler.HandlePacket(Player player, Byte[] packet) в D:\MuProject\TheServer\OpenMU-1\src\GameServer\MessageHandler\WarpGateHandler.cs:строка 50
   в MUnique.OpenMU.GameServer.ConfigurablePacketHandler.HandlePacket(Player player, Byte[] packet) в D:\MuProject\TheServer\OpenMU-1\src\GameServer\ConfigurablePacketHandler.cs:строка 56
   в MUnique.OpenMU.GameServer.RemoteView.RemotePlayer.PacketReceived(Byte[] buffer) в D:\MuProject\TheServer\OpenMU-1\src\GameServer\RemoteView\RemotePlayer.cs:строка 71

Steps to reproduce:

  1. Change INACCURACY to 4
  2. Enter Devias via Lorencia gate
  3. Leave Devias -> Enter Lorencia
  4. Enter Devias again
  5. Try to leave Devias via Lorencia gate

Upd.
Error occures at

public void EnterGate(Player player, EnterGate enterGate){
...
player.WarpTo(enterGate.TargetGate);
...
}

Because of enterGate.TargetGate == NULL.
targetGateId is ok but rawTargetGate and targetGate become NULL.

Admin panel not working on Windows

So I've just installed VS2017 with .net worload. Server starts (I guess, everything's green in console), but I've got blank page and errors in web console:

Loading failed for the <script> with source “http://localhost:1234/content/js/app.js”. admin:13
Loading failed for the <script> with source “http://localhost:1234/components/App”. admin:1
Error: "Fetching http://localhost:1234/components/App
  Instantiating http://localhost:1234/components/App
  Loading components/App"
ahttp://localhost:1234/content/js/system-production.js:4:11962

There was a problem earlier with unhanled exception which I fixed by typing command left in comment in elevated command prompt: netsh http add urlacl http://+:1234/ user=[Username] where username I've wrote my OS user name.

I've tried to install "JavaScript & TypeScript Language Support" package but no luck.

Using latest VS2017 Community, Win10 Enterprise

Couple of questions

Hey,

First of all, I really like this project and I'm looking forward to it. I am not much of a Game Server specialist but I know a little bit of C#. I am mainly a Web Developer in the MEVN stack.

How do you deal with synchronizing the Client and the Server when the client is altered (Cheat Engine for example)?
What's the performance like? C# is a lot cleaner and easier to maintain but it's not used in games for various performance reasons. This is of course not really a game and I am no specialist, just wondering how would it compare to a classic MU Server written in C++, with, let's say, 500 users online.

Why did you choose React for the frontend and why mix it with jQuery and Bootstrap?

I would like to contribute after I familiarize myself with the code for a bit.

Thank you!

Item repair is free

As you can see in this TODO, the item repair costs no money yet.
The money amount depends on how much of the item durability is missing and if the player is repairing himself by using the inventory, or using an NPC. The NPC also offers a function to repair all items at once - except pets. This method is cheaper than repairing through the inventory method.

So we should first out how the costs are calculated (I guess somehow by the ItemPriceCalculator and a multiplicator) in which case and then apply it to the ItemRepairAction.

Quick disconnect after login packet leaves the account online forever

When a client connects to the game server, sends a login packet and right after that disconnects from the game server, the client stays 'logged in' in the login server forever.
The Connection class usually receives the data before getting the disconnect message at EndReceive.
However, it could be possible that the "LastOperation" of the SocketAsyncEventArgs is a disconnect and contains data in the Buffer, too. Then the method raises a disconnect event before handling the incoming packet. Because the login process takes a bit of time, it could first do all the logout logic and afterwards logs the account in with the handled packet.

After Item Consume, Game Client can't consume next item

After consuming an item (e.g. health potion), the client probably needs an additional specific response.
Currently, you can't consume the next item. However, item durability and effects are applied for the first consumed item.

ConnectServer - servers list empty

I found a bug.

  1. Run CS
  2. Try connect to CS from client - no any gs(ok), packet was cached
  3. Run GS
  4. Try connect to CS from client - no any gs(fail), packet from cache

ConnectServer.cs line 139 - it should be this.ServerList.InvalidateCache(); after add gs.

Item stacking in Inventory

When moving the same kind of an item to another, or picking it up, it should be possible that the item is automatically stacked up to it's maximum amount on one item slot. I'm not sure if that works for move on the official servers, but it would be nice to have even when not.

Example (move):
Move health potion to another health potion -> They are getting merged on one item slot up to 3 pieces
Example (pickup):
Pick up a health potion off the ground, having another health potion in the inventory -> They are getting merged on one item slot up to 3 pieces

The amount of the stacked item is transmitted to the game client in the same field as the durability. Durability is usually only relevant for equippable items - stackable items are not equippable -> works.

It's probably required to extend the ItemDefintion by a flag 'Stackable' or a field 'MaxmiumNumberOfPieces' to be able to define this for a certain kind of item.

Let GameMap manage object ids

Currently, each object on a GameServer has an Id which is unique within the GameServer instance.
I think it would be beneficial to let the GameMap manage the Ids. That means, each object is unique within the same GameMap instance.

As there are no inter-map operations between the players where the id is involved, this should be no problem.

Of course, the game client will have a problem with a changing id of the own player. We could just send some fixed id (e.g. 0x2020) to it when sending data packets to it referencing the own player. For the packets sent to other players, it would send the "public" id for this player, managed by the GameMap.

There are several benefits:

  • More free ids (not a real limitation, but still)
  • This makes the life easier when implementing map instances which should be accessible from several servers, e.g. Loren Valley and Crywolf maps. When we don't want to implement the error-prone process of forcing the game client to connect to another game server (different ip+port), this will greatly enhance player experience. For example, partys will stay intact and the whole map change process is faster.

Use Span<T> (and Pipe API) for network code and packet handling

C# offers a new way to handle pieces of arrays: C# - All About Span: Exploring a New .NET Mainstay. I think it could help to improve the performance in the network code and would result in a lower amount of heap allocations in this project. This means, the garbage collector would have less work to do.

Currently, we make good use of byte arrays, e.g. for every received network packet at least one byte array is created. If a packet was encrypted, e.g. by SimpleModulus, even more byte arrays are created.

Migration to .net standard and .net core

The most projects should have no problems to be migrated to .net standard and .net core. This should give us some performance improvements and of course a better cross-platform support.

Basically, library projects should be migrated to .net standard and executeables to .net core.

Of course, some tools with WinForms UI probably have to stay with .net 4.6.1 for now. In the future there might be compatibility packs to migrate them as well.

JsonObjectLoader - Prevent serializing of back-references

I tried to get the JsonObjectLoader working for Accounts, as their structure can get very complex, too. Imagine an account filled full of items which have a lot of item options...

This generally works but has some issues. For example an ItemStorage loads it's items, and items load the item storage which tries to load it's items again... and so on. So the JsonObjectLoader needs some adjustments to handle this case.
See also #10.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.