Jump to content
Returning Members: Password Reset Required ×

OpenConquer: My first conquer server emulation project


Recommended Posts

Posted (edited)

Hey everyone, I may be sharing this project prematurely out of excitement lol. There is not much here yet, and what is here is nothing new or special really. Sharing for feedback and for anyone interested in following my journey down this little adventure.

Preface (feel free to skip):
About a month or so ago I got an itch to mess around with conquer online this old game I used to love. Just wanted to hop in and look around (not the retail version of course haha) one rabbit hole lead to another and now here I am. I have never worked on a game server before this project. My development velocity has been... slow to say the least but thats because im really trying to take my time and learn as much as I can in this process, and further more try to avoid the dreaded scrapping of the project because of an eventual roadblock caused by a design oversight. As much as I can with my limited knowledge on this topic. 

Credits: All credits go to whoever's code you recognize, if you see any. A lot of the ideas and implementation here was taken either directly or with a grain of salt from either Comet or Albetros. I claim nothing here, as nothing Ive done so far would be possible for me without the leg work the community has done. 


Some details on what the project does now this thread will be updated as the project gets updated, I will try my best to have daily commits for anyone interested in following. 

 - Right now the server is implemented up to the point where we respond to the client to the create player packet 

https://github.com/berniemackie97/OpenConquer
 

 

 8/23/2025 first update. dont remember the current state just pushed up what I had when I was last working on this a few weeks ago. Will be coming back to this soon, what I'm working on now should make working on the server easier

Edited by Berniemack
update
  • 3 weeks later...
Posted

fix erorr

 

using Microsoft.EntityFrameworkCore;
using OpenConquer.Domain.Contracts;
using OpenConquer.GameServer;
using OpenConquer.GameServer.Calculations.Implementation;
using OpenConquer.GameServer.Calculations.Interface;
using OpenConquer.GameServer.Dispatchers;
using OpenConquer.GameServer.Handlers;
using OpenConquer.GameServer.Queues;
using OpenConquer.GameServer.Session.Managers;
using OpenConquer.GameServer.Workers;
using OpenConquer.Infrastructure.Mapping;
using OpenConquer.Infrastructure.Persistence.Context;
using OpenConquer.Infrastructure.POCO;
using OpenConquer.Infrastructure.Services;
using OpenConquer.Protocol.Packets.Parsers;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Configuration.SetBasePath(AppContext.BaseDirectory).AddJsonFile("appsettings.shared.json", optional: false, reloadOnChange: true).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).AddEnvironmentVariables();

builder.Services.Configure<NetworkSettings>(builder.Configuration.GetSection("Network"));

MapsterConfig.RegisterMappings();

builder.Services.AddDbContext<AccountDataContext>(opts => opts.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
builder.Services.AddDbContext<GameDataContext>(opts => opts.UseNpgsql(builder.Configuration.GetConnectionString("Default")));

builder.Services.AddScoped<ExperienceService>();
builder.Services.AddScoped<IExperienceService>(sp => sp.GetRequiredService<ExperienceService>());

builder.Services.AddScoped<UserManager>();
builder.Services.AddScoped<ILevelStatService, LevelStatService>();
builder.Services.AddScoped<IAccountService, AccountService>();
builder.Services.AddScoped<ICharacterService, CharacterService>();

builder.Services.Scan(scan => scan.FromAssemblyOf<IPacketParser>().AddClasses(classes => classes.AssignableTo<IPacketParser>()).AsImplementedInterfaces().WithSingletonLifetime());
builder.Services.Scan(scan => scan.FromAssemblyOf<PacketDispatcher>().AddClasses(classes => classes.AssignableTo(typeof(IPacketHandler<>))).AsImplementedInterfaces().WithTransientLifetime());

builder.Services.AddSingleton<PacketDispatcher>();
builder.Services.AddSingleton<WorldManager>();
builder.Services.AddSingleton<ExperienceService>();
builder.Services.AddSingleton<ConnectionQueue>();
builder.Services.AddSingleton<IExperienceService>(sp => sp.GetRequiredService<ExperienceService>());


builder.Services.AddHostedService(sp => sp.GetRequiredService<ExperienceService>());
builder.Services.AddHostedService<GameHandshakeService>();
builder.Services.AddHostedService<ConnectionWorker>();

IHost host = builder.Build();
host.Run();

 

Posted (edited)

Its not currently playable, I'd guess the error youre facing is the missing appsettings.shared.json, since you didnt give me the error you got just the program.cs file. Either way, I wouldnt expect much progress on this for a few more months. Life things, plus I've shifted partial focus to trying to deob the client to release along with this if I can, if not hopefully some useful tools or info comes out of it at least. Feel free to dm me if you have specific issues with at least building the project I'll try to help you get set up. 


Although I do remember there were other errors at some point in time with my with my AddScoped's, I'll update the repo this weekend, here's what I currently have 

 

using Microsoft.EntityFrameworkCore;
using OpenConquer.Domain.Contracts;
using OpenConquer.GameServer;
using OpenConquer.GameServer.Calculations.Implementation;
using OpenConquer.GameServer.Calculations.Interface;
using OpenConquer.GameServer.Dispatchers;
using OpenConquer.GameServer.Handlers;
using OpenConquer.GameServer.Queues;
using OpenConquer.GameServer.Session.Managers;
using OpenConquer.GameServer.Workers;
using OpenConquer.Infrastructure.Mapping;
using OpenConquer.Infrastructure.Persistence.Context;
using OpenConquer.Infrastructure.POCO;
using OpenConquer.Infrastructure.Services;
using OpenConquer.Protocol.Crypto;
using OpenConquer.Protocol.Packets.Parsers;
using OpenConquer.Protocol.Utilities;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Configuration.SetBasePath(AppContext.BaseDirectory).AddJsonFile("appsettings.shared.json", optional: false, reloadOnChange: true).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).AddEnvironmentVariables();

builder.Services.Configure<NetworkSettings>(builder.Configuration.GetSection("Network"));

builder.Services.AddDbContextFactory<DataContext>(opts => opts.UseMySql(builder.Configuration.GetConnectionString("Default"), new MySqlServerVersion(new Version(8, 0, 36))));

MapsterConfig.RegisterMappings();

builder.Services.Scan(scan => scan.FromAssemblyOf<IPacketParser>().AddClasses(c => c.AssignableTo<IPacketParser>()).AsImplementedInterfaces().WithSingletonLifetime());

builder.Services.AddSingleton<PacketParserRegistry>();

builder.Services.Scan(scan => scan.FromAssemblyOf<PacketDispatcher>().AddClasses(c => c.AssignableTo(typeof(IPacketHandler<>))).AsImplementedInterfaces().WithTransientLifetime());

builder.Services.AddScoped<IAccountService, AccountService>();
builder.Services.AddScoped<ICharacterService, CharacterService>();

builder.Services.AddSingleton<ILevelStatService, LevelStatService>();

builder.Services.AddSingleton<UserManager>();
builder.Services.AddSingleton<WorldManager>();

builder.Services.AddSingleton<PacketDispatcher>();

builder.Services.AddSingleton<ExperienceService>();
builder.Services.AddSingleton<IExperienceService>(sp => sp.GetRequiredService<ExperienceService>());
builder.Services.AddHostedService(sp => sp.GetRequiredService<ExperienceService>());

builder.Services.AddSingleton<ConnectionQueue>();
builder.Services.AddHostedService<ConnectionWorker>();

builder.Services.AddHostedService<GameHandshakeService>();

IHost host = builder.Build();
host.Run();

for the appsettings file just make it and put it in your debug folder

{
    "Network": {
        "LoginPort": 9959,
        "GamePort": 5816,
        "ExternalIp": ""
    },
    "ConnectionStrings": {
        "Default": "Server=localhost;Port=3306;Database=openco;User=root;Password=;"
    }
}


 

Edited by Berniemack
Posted (edited)

Took a quick look and it looks pretty clean, nice work. 
 

I do have 2 small feedback points based on the comments here and something I didn’t see. 

1. You don’t need a appsettings.shared.json, you can just put them in appsettings.json. If you need to override them, you can do so in another appsettings file. 
 

2. I didn’t see a globals file. If add a globals file in a project, you can add the most commonly used using statements in there. This will help clean up the using statements in all files in that project. 

Edited by Omicron
Posted
On 8/22/2025 at 6:49 AM, BLACK said:

fix erorr

 

using Microsoft.EntityFrameworkCore;
using OpenConquer.Domain.Contracts;
using OpenConquer.GameServer;
using OpenConquer.GameServer.Calculations.Implementation;
using OpenConquer.GameServer.Calculations.Interface;
using OpenConquer.GameServer.Dispatchers;
using OpenConquer.GameServer.Handlers;
using OpenConquer.GameServer.Queues;
using OpenConquer.GameServer.Session.Managers;
using OpenConquer.GameServer.Workers;
using OpenConquer.Infrastructure.Mapping;
using OpenConquer.Infrastructure.Persistence.Context;
using OpenConquer.Infrastructure.POCO;
using OpenConquer.Infrastructure.Services;
using OpenConquer.Protocol.Packets.Parsers;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Configuration.SetBasePath(AppContext.BaseDirectory).AddJsonFile("appsettings.shared.json", optional: false, reloadOnChange: true).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).AddEnvironmentVariables();

builder.Services.Configure<NetworkSettings>(builder.Configuration.GetSection("Network"));

MapsterConfig.RegisterMappings();

builder.Services.AddDbContext<AccountDataContext>(opts => opts.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
builder.Services.AddDbContext<GameDataContext>(opts => opts.UseNpgsql(builder.Configuration.GetConnectionString("Default")));

builder.Services.AddScoped<ExperienceService>();
builder.Services.AddScoped<IExperienceService>(sp => sp.GetRequiredService<ExperienceService>());

builder.Services.AddScoped<UserManager>();
builder.Services.AddScoped<ILevelStatService, LevelStatService>();
builder.Services.AddScoped<IAccountService, AccountService>();
builder.Services.AddScoped<ICharacterService, CharacterService>();

builder.Services.Scan(scan => scan.FromAssemblyOf<IPacketParser>().AddClasses(classes => classes.AssignableTo<IPacketParser>()).AsImplementedInterfaces().WithSingletonLifetime());
builder.Services.Scan(scan => scan.FromAssemblyOf<PacketDispatcher>().AddClasses(classes => classes.AssignableTo(typeof(IPacketHandler<>))).AsImplementedInterfaces().WithTransientLifetime());

builder.Services.AddSingleton<PacketDispatcher>();
builder.Services.AddSingleton<WorldManager>();
builder.Services.AddSingleton<ExperienceService>();
builder.Services.AddSingleton<ConnectionQueue>();
builder.Services.AddSingleton<IExperienceService>(sp => sp.GetRequiredService<ExperienceService>());


builder.Services.AddHostedService(sp => sp.GetRequiredService<ExperienceService>());
builder.Services.AddHostedService<GameHandshakeService>();
builder.Services.AddHostedService<ConnectionWorker>();

IHost host = builder.Build();
host.Run();

 

Very rude... Just dumping code here and saying to fix the error without even adding the error message /facepalm.

------

On another note, very cool project OP! Love these kinds of projects

Posted (edited)
3 hours ago, Omicron said:

Can’t seem to update my previous post… 

Got some questions too, I noticed that you used PostgresSql and MySQL. Do you mind elaborating? 
 

Another tip to help improve performance: disable data tracking by EF where you don’t need it. 
https://dotnetbenchmarks.com/benchmark/1079

Thanks for the suggestions! Just using MySQL, any PostgresSQL stuff is just uncleaned up code from playing around with ideas. The reason for the appsettings.shared.json is I was toying around with separating some things that I plan on putting in a regular appsettings.json. May not end up doing that at all though so, It may end up just being an appsettings.json in the end. 

Will definitely look into disabling tracking, and possibly using a globals file, I'll see if I like it for this. Again thank you for taking the time to look at my project and give me some kind feedback! I will be updating the repo at some point today 

 

Edited by Berniemack
Posted
6 minutes ago, Tkblackbelt said:

Very rude... Just dumping code here and saying to fix the error without even adding the error message /facepalm.

------

On another note, very cool project OP! Love these kinds of projects

Thank you! Haven't updated in a bit but I'm still hard at work at this whenever I can get the time to work on it. Will update the thread when I get some time today to update the repo. (Mostly refactoring changes still "stuck" on the dhkey exchange, really I've mostly just so happened to have shifted focus on working on another part of this project). 

Posted

Good job! I haven't looked through the project too much, but it looks like you're following the hosted services factory pattern? Would be interested to know your thoughts around using it, and if you'd recommend it for C# game server development. I experimented a little with it for Comet's randomization service (BackgroundService using the host service pattern), but never implemented any game systems with it. Best of luck with your development! 

Posted
2 hours ago, Spirited said:

Good job! I haven't looked through the project too much, but it looks like you're following the hosted services factory pattern? Would be interested to know your thoughts around using it, and if you'd recommend it for C# game server development. I experimented a little with it for Comet's randomization service (BackgroundService using the host service pattern), but never implemented any game systems with it. Best of luck with your development! 

I am indeed leaning into the generic host + BackgroundService pattern but only for LoginHandshakeService, GameHandshakeService, ConnectionWorker and im currently experimenting with an ExperienceService but im not really liking how I have that set up (no real reason other than I feel like there probably is a better way to do what im currently doing with it). Everything else is regular old DI, Parsers and handlers are discovered through assembly scanning. So far I dont have any complaints, I do have to say this is my introduction to game server development as a whole, so I dont know if i can really recommend anything to anyone, other than say so far for me it fits my needs. I really probably should read more into the topic and see more about why things are done a certain way in other game servers. 

Thank you!

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...