├── _backup ├── README.MD └── lobbyemu-master.zip ├── runRelease.sh ├── sonar-project.properties ├── FragmentNetslumServer ├── Services │ ├── Interfaces │ │ ├── IDatabaseAccessor.cs │ │ ├── IRankingManagementService.cs │ │ ├── INewsService.cs │ │ ├── IBaseService.cs │ │ ├── IOpCodeHandler.cs │ │ ├── IBulletinBoardService.cs │ │ ├── IOpCodeProviderService.cs │ │ ├── IGuildManagementService.cs │ │ ├── IMailService.cs │ │ ├── IClientConnectionService.cs │ │ ├── IClientProviderService.cs │ │ └── ILobbyChatService.cs │ ├── GameClientService.cs │ └── LobbyChatService.cs ├── Models │ ├── MessageOfTheDayModel.cs │ ├── BbsCategoryModel.cs │ ├── BbsPostBody.cs │ ├── BbsThreadModel.cs │ ├── NewsSectionLogModel.cs │ ├── PlayerAccountIDModel.cs │ ├── PlayerClass.cs │ ├── MailBodyModel.cs │ ├── Mapping │ │ ├── MessageOfTheDayModel.hbm.xml │ │ ├── PlayerAccountIDModel.hbm.xml │ │ ├── BbsCategoryModel.hbm.xml │ │ ├── NewsSectionLogModel.hbm.xml │ │ ├── BbsThreadModel.hbm.xml │ │ ├── BbsPostBody.hbm.xml │ │ ├── MailBodyModel.hbm.xml │ │ ├── NewsSectionModel.hbm.xml │ │ ├── BbsPostMetaModel.hbm.xml │ │ ├── MailMetaModel.hbm.xml │ │ ├── RankingDataModel.hbm.xml │ │ ├── GuildItemShopModel.hbm.xml │ │ ├── GuildRepositoryModel.hbm.xml │ │ └── CharacterRepositoryModel.hbm.xml │ ├── MailMetaModel.cs │ ├── BbsPostMetaModel.cs │ ├── GuildItemShopModel.cs │ ├── GuildRepositoryModel.cs │ ├── RankingDataModel.cs │ ├── NewsSectionModel.cs │ └── CharacterRepositoryModel.cs ├── Entities │ ├── OpCodeHandlers │ │ ├── Data │ │ │ ├── OPCODE_DATA_0X771E.cs │ │ │ ├── BBS │ │ │ │ ├── OPCODE_DATA_0x780F.cs │ │ │ │ ├── OPCODE_DATA_BBS_GET_UPDATES.cs │ │ │ │ ├── OPCODE_DATA_BBS_POST.cs │ │ │ │ ├── OPCODE_DATA_BBS_THREAD_GET_CONTENT.cs │ │ │ │ ├── OPCODE_DATA_BBS_THREAD_GETMENU.cs │ │ │ │ └── OPCODE_DATA_BBS_GETMENU.cs │ │ │ ├── OPCODE_DATA_0x787B.cs │ │ │ ├── OPCODE_DATA_DISKID.cs │ │ │ ├── OPCODE_DATA_LOGON_REPEAT.cs │ │ │ ├── OPCODE_DATA_UNREGISTER_CHAR.cs │ │ │ ├── AreaServer │ │ │ │ ├── OPCODE_DATA_AS_PUBLISH.cs │ │ │ │ ├── OPCODE_DATA_LOGON_AS2.cs │ │ │ │ ├── OPCODE_DATA_AS_DISKID.cs │ │ │ │ ├── OPCODE_DATA_AS_UPDATE_USERNUM.cs │ │ │ │ ├── OPCODE_DATA_AS_UPDATE_STATUS.cs │ │ │ │ ├── OPCODE_DATA_AS_PUBLISH_DETAILS.cs │ │ │ │ └── OPCODE_DATA_AS_IPPORT.cs │ │ │ ├── OPCODE_DATA_0x787E.cs │ │ │ ├── OPCODE_DATA_COM.cs │ │ │ ├── OPCODE_DATA_SELECT_CHAR.cs │ │ │ ├── OPCODE_DATA_SELECT2_CHAR.cs │ │ │ ├── Lobby │ │ │ │ ├── OPCODE_DATA_LOBBY_GETSERVERS.cs │ │ │ │ ├── OPCODE_DATA_LOBBY_GETSERVERS_EXIT.cs │ │ │ │ ├── OPCODE_DATA_LOBBY_CHATROOM_GETLIST.cs │ │ │ │ ├── OPCODE_DATA_LOBBY_EVENT.cs │ │ │ │ ├── OPCODE_DATA_LOBBY_STATUS_UPDATE.cs │ │ │ │ ├── OPCODE_DATA_LOBBY_EXITROOM.cs │ │ │ │ ├── OPCODE_DATA_LOBBY_GETMENU.cs │ │ │ │ ├── OPCODE_DATA_LOBBY_ENTERROOM.cs │ │ │ │ └── OPCODE_DATA_LOBBY_GETSERVERS_GETLIST.cs │ │ │ ├── OPCODE_DATA_RETURN_DESKTOP.cs │ │ │ ├── Guild │ │ │ │ ├── OPCODE_DATA_GUILD_DONATE_COINS.cs │ │ │ │ ├── OPCODE_DATA_GUILD_DISSOLVED.cs │ │ │ │ ├── OPCODE_DATA_GUILD_BUY_ITEM.cs │ │ │ │ ├── OPCODE_DATA_GUILD_GET_DONATION_SETTINGS.cs │ │ │ │ ├── OPCODE_DATA_GUILD_UPDATE_DETAILS.cs │ │ │ │ ├── OPCODE_DATA_GUILD_LOGGEDIN_MEMBERS.cs │ │ │ │ ├── OPCODE_DATA_GUILD_PLAYER_LEAVING.cs │ │ │ │ ├── OPCODE_DATA_GUILD_CREATE.cs │ │ │ │ ├── OPCODE_DATA_GUILD_UPDATEITEM_PRICING.cs │ │ │ │ ├── OPCODE_DATA_GUILD_GET_INFO.cs │ │ │ │ ├── OPCODE_DATA_GUILD_PLAYER_KICKED.cs │ │ │ │ ├── OPCODE_DATA_GUILD_VIEW.cs │ │ │ │ ├── OPCODE_DATA_GUILD_GM_LEAVING.cs │ │ │ │ ├── OPCODE_DATA_ACCEPT_GUILD_INVITE.cs │ │ │ │ ├── OPCODE_DATA_GUILD_DONATE_ITEM.cs │ │ │ │ ├── OPCODE_DATA_GUILD_GETITEMS.cs │ │ │ │ ├── OPCODE_DATA_GUILD_GETITEMS_TOBUY.cs │ │ │ │ ├── OPCODE_DATA_GUILD_TAKE_GP.cs │ │ │ │ ├── OPCODE_DATA_INVITE_TO_GUILD.cs │ │ │ │ ├── OPCODE_DATA_GUILD_GET_LIST_OF_ITEMS.cs │ │ │ │ ├── OPCODE_DATA_GUILD_TAKE_ITEM.cs │ │ │ │ ├── OPCODE_DATA_GUILD_UPDATEITEM_PRICING_AVAILABILITY.cs │ │ │ │ ├── OPCODE_DATA_GUILD_MEMBERLIST.cs │ │ │ │ ├── OPCODE_DATA_GUILD_GET_ALL_GUILDS.cs │ │ │ │ └── OPCODE_DATA_GUILD_GETMENU.cs │ │ │ ├── Mail │ │ │ │ ├── OPCODE_DATA_GUILD_MAIL_SEND.cs │ │ │ │ ├── OPCODE_DATA_MAILCHECK.cs │ │ │ │ ├── OPCODE_DATA_MAIL_SEND.cs │ │ │ │ ├── OPCODE_DATA_MAIL_GET_MAIL_BODY.cs │ │ │ │ └── OPCODE_DATA_MAIL_GET.cs │ │ │ ├── Ranking │ │ │ │ ├── OPCODE_RANKING_VIEW_PLAYER.cs │ │ │ │ └── OPCODE_RANKING_VIEW_ALL.cs │ │ │ ├── OPCODE_DATA_0x788C.cs │ │ │ ├── News │ │ │ │ ├── OPCODE_DATA_NEWCHECK.cs │ │ │ │ ├── OPCODE_DATA_NEWS_GETPOST.cs │ │ │ │ └── OPCODE_DATA_NEWS_GETMENU.cs │ │ │ ├── OPCODE_DATA_LOGON.cs │ │ │ ├── OPCODE_DATA_SAVEID.cs │ │ │ ├── OPCODE_DATA_NORESPONSE.cs │ │ │ └── OPCODE_DATA_REGISTER_CHAR.cs │ │ ├── Regular │ │ │ ├── OPCODE_UNKNOWN.cs │ │ │ ├── OPCODE_KEY_EXCHANGE_ACKNOWLEDGMENT.cs │ │ │ └── OPCODE_KEY_EXCHANGE_REQUEST.cs │ │ ├── NoResponseOpCodeHandler.cs │ │ └── SimpleResponseOpCodeHandler.cs │ ├── Attributes │ │ ├── OpCodeAttribute.cs │ │ └── OpCodeDataAttribute.cs │ └── RequestContent.cs ├── Enumerations │ └── ServiceStatusEnum.cs ├── Exceptions │ └── LobbyEmuCrashException.cs ├── Config.cs ├── Helpers │ └── IPAddressHelpers.cs └── FragmentNetslumServer.csproj ├── FragmentNetslumServerPubSub ├── FragmentNetslumServerPubSub.csproj └── Ioc │ ├── Interfaces │ ├── IPubSubPipelineFactory.cs │ ├── ISubscriber.cs │ └── IPublisher.cs │ └── Implementations │ ├── Publisher.cs │ ├── PubSubPipelineFactory.cs │ └── Subscriber.cs ├── FragmentNetslumServerWebApi ├── appsettings.Development.json ├── appsettings.json ├── FragmentNetslumServerWebApi.csproj ├── Program.cs ├── Models │ ├── ClientsModel.cs │ ├── AreaServerModel.cs │ └── PlayerModel.cs ├── Controllers │ ├── RefreshNewsSection.cs │ ├── RefreshMOD.cs │ ├── DebugController.cs │ └── StatusPageController.cs ├── Properties │ └── launchSettings.json └── Startup.cs ├── .travis.yml ├── FragmentNetslumServer.sln.DotSettings ├── .gitattributes ├── .gitignore ├── FragmentNetslumServerLauncher └── FragmentNetslumServerLauncher.csproj ├── settings.ini.example ├── README.MD └── FragmentNetslumServer.sln /_backup/README.MD: -------------------------------------------------------------------------------- 1 | source: https://github.com/Lord-Ptolemy/lobbyemu 2 | date: 10.03.2017 -------------------------------------------------------------------------------- /_backup/lobbyemu-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zackmon/FragmentNetslumServer/HEAD/_backup/lobbyemu-master.zip -------------------------------------------------------------------------------- /runRelease.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./FragmentNetslumServerLauncher/bin/Release/net6.0/FragmentNetslumServerLauncher 4 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | # must be unique in a given SonarQube instance 2 | sonar.projectKey=Zackmon_FragmentServer_netCore 3 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IDatabaseAccessor.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Services.Interfaces 2 | { 3 | class IDatabaseAccessor 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /FragmentNetslumServerPubSub/FragmentNetslumServerPubSub.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/MessageOfTheDayModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class MessageOfTheDayModel 4 | { 5 | public virtual int Id { get; set; } 6 | public virtual string Message { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/BbsCategoryModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class BbsCategoryModel 4 | { 5 | public virtual int categoryID { get; set; } 6 | public virtual string categoryName { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /FragmentNetslumServerPubSub/Ioc/Interfaces/IPubSubPipelineFactory.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServerPubSub.Ioc.Interfaces 2 | { 3 | 4 | public interface IPubSubPipelineFactory 5 | { 6 | IPublisher GetPublisher(); 7 | ISubscriber GetSubscriber(); 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/BbsPostBody.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class BbsPostBody 4 | { 5 | public virtual int postBodyID {get; set; } 6 | public virtual byte[] postBody { get; set;} 7 | public virtual int postID { get; set;} 8 | } 9 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/BbsThreadModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class BbsThreadModel 4 | { 5 | public virtual int threadID { get; set; } 6 | public virtual byte[] threadTitle { get; set; } 7 | public virtual int categoryID { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/NewsSectionLogModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class NewsSectionLogModel 4 | { 5 | public virtual int Id { get; set; } 6 | public virtual string SaveId { get; set; } 7 | public virtual ushort ArticleId { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | solution: FragmentNetslumServer.sln 3 | mono: none 4 | dotnet: 6.0.100 5 | script: 6 | - dotnet restore 7 | - dotnet build -c Release 8 | - sonar-scanner 9 | addons: 10 | sonarcloud: 11 | organization: "zackmon" # the key of the org you chose at step #3 12 | 13 | 14 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/PlayerAccountIDModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class PlayerAccountIDModel 4 | { 5 | public virtual int ID { get; set; } 6 | public virtual string saveID { get; set; } 7 | 8 | public PlayerAccountIDModel() 9 | { 10 | ID = -1; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/FragmentNetslumServerWebApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/PlayerClass.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | // 0 = Twin Blade, 1 = Blademaster, 2 = Heavy Blade, 3 = Heavy Axe, 4 = Long Arm, 5 = Wavemaster 4 | public enum PlayerClass 5 | { 6 | TwinBlade, 7 | BladeMaster, 8 | HeavyBlade, 9 | HeavyAxe, 10 | LongArm, 11 | WaveMaster 12 | } 13 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/MailBodyModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class MailBodyModel 4 | { 5 | public virtual int Mail_Body_ID { get; set; } 6 | public virtual int Mail_ID { get; set; } 7 | public virtual byte[] Mail_Body { get; set; } 8 | public virtual string Mail_Face_ID { get; set; } 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_0X771E.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | 3 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 4 | { 5 | [OpCodeData(0x771E)] 6 | public sealed class OPCODE_DATA_0X771E : SimpleResponseOpCodeHandler 7 | { 8 | public OPCODE_DATA_0X771E() : base(0x771F, new byte[] { 0x00, 0x00 }) { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FragmentNetslumServer.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | True -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/BBS/OPCODE_DATA_0x780F.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | 3 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.BBS 4 | { 5 | [OpCodeData(0x780F)] 6 | public sealed class OPCODE_DATA_0x780F : SimpleResponseOpCodeHandler 7 | { 8 | public OPCODE_DATA_0x780F() : base(0x7810, new byte[] { 0x01, 0x92 }) { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Regular/OPCODE_UNKNOWN.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using System.ComponentModel; 3 | 4 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Regular 5 | { 6 | [OpCode(0x0002), DisplayName("Unknown Handler"), Description("Handles an opcode that seemingly has no function")] 7 | public sealed class OPCODE_UNKNOWN : NoResponseOpCodeHandler { } 8 | } 9 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_0x787B.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | 3 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 4 | { 5 | [OpCodeData(0x787B)] 6 | public sealed class OPCODE_DATA_0x787B : SimpleResponseOpCodeHandler 7 | { 8 | public OPCODE_DATA_0x787B() : base(0x787C, new byte[] { 0x00, 0x00 }) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IRankingManagementService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace FragmentNetslumServer.Services.Interfaces 4 | { 5 | public interface IRankingManagementService : IBaseService 6 | { 7 | List GetPlayerRanking(ushort categoryID, ushort classID); 8 | List GetRankingCategory(); 9 | byte[] GetRankingPlayerInfo(uint playerID); 10 | } 11 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_DISKID.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | 3 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 4 | { 5 | [OpCodeData(OpCodes.OPCODE_DATA_DISKID)] 6 | public sealed class OPCODE_DATA_DISKID : SimpleResponseOpCodeHandler 7 | { 8 | public OPCODE_DATA_DISKID() : base(OpCodes.OPCODE_DATA_DISKID_OK, new byte[] { 0x36, 0x36, 0x31, 0x36 }) { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/BBS/OPCODE_DATA_BBS_GET_UPDATES.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | 3 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.BBS 4 | { 5 | [OpCodeData(OpCodes.OPCODE_DATA_BBS_GET_UPDATES)] 6 | public sealed class OPCODE_DATA_BBS_GET_UPDATES : SimpleResponseOpCodeHandler 7 | { 8 | public OPCODE_DATA_BBS_GET_UPDATES() : base(0x786b, new byte[] { 0x00, 0x00 }) { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_LOGON_REPEAT.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | 3 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 4 | { 5 | [OpCodeData(OpCodes.OPCODE_DATA_LOGON_REPEAT)] 6 | public sealed class OPCODE_DATA_LOGON_REPEAT : SimpleResponseOpCodeHandler 7 | { 8 | public OPCODE_DATA_LOGON_REPEAT() : base(OpCodes.OPCODE_DATA_LOGON_RESPONSE, new byte[] { 0x02, 0x10 }) { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_UNREGISTER_CHAR.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | 3 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 4 | { 5 | [OpCodeData(OpCodes.OPCODE_DATA_UNREGISTER_CHAR)] 6 | public sealed class OPCODE_DATA_UNREGISTER_CHAR : SimpleResponseOpCodeHandler 7 | { 8 | public OPCODE_DATA_UNREGISTER_CHAR() : base(OpCodes.OPCODE_DATA_UNREGISTER_CHAROK, new byte[] { 0x00, 0x00 }) { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/AreaServer/OPCODE_DATA_AS_PUBLISH.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | 3 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.AreaServer 4 | { 5 | [OpCodeData(OpCodes.OPCODE_DATA_AS_PUBLISH)] 6 | public sealed class OPCODE_DATA_AS_PUBLISH : SimpleResponseOpCodeHandler 7 | { 8 | public OPCODE_DATA_AS_PUBLISH() : base(OpCodes.OPCODE_DATA_AS_PUBLISH_OK, new byte[] { 0x00, 0x00 }) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /FragmentNetslumServerPubSub/Ioc/Implementations/Publisher.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServerPubSub.Core; 2 | using FragmentNetslumServerPubSub.Ioc.Interfaces; 3 | 4 | namespace FragmentNetslumServerPubSub.Ioc.Implementations 5 | { 6 | 7 | public class Publisher : IPublisher 8 | { 9 | private readonly Hub hub; 10 | 11 | public Publisher( Hub hub ) 12 | { 13 | this.hub = hub; 14 | } 15 | 16 | public void Publish(T data) => hub.Publish(data); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/AreaServer/OPCODE_DATA_LOGON_AS2.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using System.ComponentModel; 3 | 4 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.AreaServer 5 | { 6 | [OpCodeData(OpCodes.OPCODE_DATA_LOGON_AS2), Description("Handles an Area Server login request (I think)")] 7 | public sealed class OPCODE_DATA_LOGON_AS2 : SimpleResponseOpCodeHandler 8 | { 9 | public OPCODE_DATA_LOGON_AS2() : base(0x701C, new byte[] { 0x02, 0x11 }) { } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/MessageOfTheDayModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/PlayerAccountIDModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /FragmentNetslumServerPubSub/Ioc/Interfaces/ISubscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FragmentNetslumServerPubSub.Ioc.Interfaces 4 | { 5 | 6 | public interface ISubscriber 7 | { 8 | bool Exists( object subscriber ); 9 | bool Exists( object subscriber, Action handler ); 10 | void Subscribe( object subscriber, Action handler ); 11 | void Unsubscribe( object subscriber ); 12 | void Unsubscribe( object subscriber ); 13 | void Unsubscribe( object subscriber, Action handler ); 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.*~ 3 | project.lock.json 4 | .DS_Store 5 | *.pyc 6 | nupkg/ 7 | 8 | # Visual Studio Code 9 | .vscode 10 | 11 | # Rider 12 | .idea 13 | 14 | # User-specific files 15 | *.suo 16 | *.user 17 | *.userosscache 18 | *.sln.docstates 19 | 20 | # Build results 21 | [Dd]ebug/ 22 | [Dd]ebugPublic/ 23 | [Rr]elease/ 24 | [Rr]eleases/ 25 | x64/ 26 | x86/ 27 | build/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Oo]ut/ 32 | msbuild.log 33 | msbuild.err 34 | msbuild.wrn 35 | 36 | # Visual Studio 2015 37 | .vs/ 38 | 39 | /FragmentServerWV/bin/ 40 | logs/ 41 | settings.ini -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_0x787E.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 8 | { 9 | [OpCodeData(0x787E)] 10 | public sealed class OPCODE_DATA_0x787E : SimpleResponseOpCodeHandler 11 | { 12 | public OPCODE_DATA_0x787E() : base(0x787F,new byte[] { 0x00, 0x00 }) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace FragmentNetslumServerWebApi 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); 16 | } 17 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/AreaServer/OPCODE_DATA_AS_DISKID.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using FragmentNetslumServer.Entities.Attributes; 3 | 4 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.AreaServer 5 | { 6 | [OpCodeData(OpCodes.OPCODE_DATA_AS_DISKID) , Description("Area Server DISK ID Check")] 7 | public sealed class OPCODE_DATA_AS_DISKID : SimpleResponseOpCodeHandler 8 | { 9 | public OPCODE_DATA_AS_DISKID() : base(OpCodes.OPCODE_DATA_AS_DISKID_OK, new byte[] { 0x00, 0x00 }) 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/BbsCategoryModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_COM.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 8 | { 9 | [OpCodeData(OpCodes.OPCODE_DATA_COM)] 10 | public sealed class OPCODE_DATA_COM : SimpleResponseOpCodeHandler 11 | { 12 | 13 | public OPCODE_DATA_COM() : base(OpCodes.OPCODE_DATA_COM_OK, new byte[] { 0xDE, 0xAD }) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FragmentNetslumServerPubSub/Ioc/Implementations/PubSubPipelineFactory.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServerPubSub.Core; 2 | using FragmentNetslumServerPubSub.Ioc.Interfaces; 3 | 4 | namespace FragmentNetslumServerPubSub.Ioc.Implementations 5 | { 6 | public class PubSubPipelineFactory : IPubSubPipelineFactory 7 | { 8 | private readonly Hub hub; 9 | 10 | public PubSubPipelineFactory() 11 | { 12 | hub = new Hub(); 13 | } 14 | 15 | public IPublisher GetPublisher() => new Publisher( hub ); 16 | 17 | public ISubscriber GetSubscriber() => new Subscriber( hub ); 18 | } 19 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/NewsSectionLogModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/MailMetaModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FragmentNetslumServer.Models 4 | { 5 | public class MailMetaModel 6 | { 7 | public virtual int Mail_ID { get; set; } 8 | public virtual int Receiver_Account_ID { get; set; } 9 | public virtual DateTime date {get; set; } 10 | public virtual int Sender_Account_ID { get; set; } 11 | public virtual byte[] Sender_Name {get; set; } 12 | public virtual byte[] Receiver_Name {get; set; } 13 | public virtual byte[] Mail_Subject {get; set; } 14 | public virtual Boolean Mail_Delivered { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/INewsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using FragmentNetslumServer.Models; 4 | 5 | namespace FragmentNetslumServer.Services.Interfaces 6 | { 7 | public interface INewsService : IBaseService 8 | { 9 | 10 | Task RefreshNewsList(); 11 | Task> GetNewsArticles(); 12 | 13 | Task> GetNewsArticles(string saveID); 14 | 15 | Task CheckIfNewNewsForSaveId(string saveId); 16 | 17 | Task UpdateNewsLog(string saveId, ushort articleId); 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_SELECT_CHAR.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 8 | { 9 | [OpCodeData(OpCodes.OPCODE_DATA_SELECT_CHAR)] 10 | public sealed class OPCODE_DATA_SELECT_CHAR : SimpleResponseOpCodeHandler 11 | { 12 | public OPCODE_DATA_SELECT_CHAR() : base(OpCodes.OPCODE_DATA_SELECT_CHAROK, new byte[] { 0x00, 0x00 }) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/BbsPostMetaModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FragmentNetslumServer.Models 4 | { 5 | public class BbsPostMetaModel 6 | { 7 | public virtual int unk0 { get; set; } 8 | public virtual int postID {get; set; } 9 | public virtual int unk2 {get; set; } 10 | public virtual DateTime date {get; set; } 11 | public virtual byte[] username {get; set; } 12 | public virtual byte[] subtitle {get; set; } 13 | public virtual byte[] title {get; set; } 14 | public virtual string unk3 {get; set; } 15 | public virtual int threadID {get; set; } 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/BbsThreadModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/BbsPostBody.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_SELECT2_CHAR.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 8 | { 9 | [OpCodeData(OpCodes.OPCODE_DATA_SELECT2_CHAR)] 10 | public sealed class OPCODE_DATA_SELECT2_CHAR : SimpleResponseOpCodeHandler 11 | { 12 | public OPCODE_DATA_SELECT2_CHAR() : base(OpCodes.OPCODE_DATA_SELECT2_CHAROK, new byte[] { 0x30, 0x30, 0x30, 0x30 }) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IBaseService.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Enumerations; 2 | 3 | namespace FragmentNetslumServer.Services.Interfaces 4 | { 5 | 6 | /// 7 | /// Defines basic information that all services should be able to provide 8 | /// 9 | public interface IBaseService 10 | { 11 | 12 | /// 13 | /// Gets a friendly display name of the service 14 | /// 15 | string ServiceName { get; } 16 | 17 | /// 18 | /// Gets the current status of the service 19 | /// 20 | ServiceStatusEnum ServiceStatus { get; } 21 | 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Lobby/OPCODE_DATA_LOBBY_GETSERVERS.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Lobby 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_LOBBY_GETSERVERS)] 11 | public sealed class OPCODE_DATA_LOBBY_GETSERVERS : SimpleResponseOpCodeHandler 12 | { 13 | public OPCODE_DATA_LOBBY_GETSERVERS() : base(OpCodes.OPCODE_DATA_LOBBY_GETSERVERS_OK, new byte[] { 0x00, 0x00 }) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Models/ClientsModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace FragmentNetslumServerWebApi.Models 4 | { 5 | public class ClientsModel 6 | { 7 | public List _playerList = new List(); 8 | public List _areaServerList = new List(); 9 | 10 | 11 | public List PlayerList 12 | { 13 | get => _playerList; 14 | set => _playerList = value; 15 | } 16 | 17 | public List AreaServerList 18 | { 19 | get => _areaServerList; 20 | set => _areaServerList = value; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/NoResponseOpCodeHandler.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Services.Interfaces; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace FragmentNetslumServer.Entities.OpCodeHandlers 6 | { 7 | /// 8 | /// A base class that does not have an actual response to the client 9 | /// 10 | public abstract class NoResponseOpCodeHandler : IOpCodeHandler 11 | { 12 | public virtual Task> HandleIncomingRequestAsync(RequestContent request) 13 | => Task.FromResult>(new[] { ResponseContent.Empty }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Lobby/OPCODE_DATA_LOBBY_GETSERVERS_EXIT.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Lobby 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_LOBBY_GETSERVERS_EXIT)] 11 | public sealed class OPCODE_DATA_LOBBY_GETSERVERS_EXIT : SimpleResponseOpCodeHandler 12 | { 13 | public OPCODE_DATA_LOBBY_GETSERVERS_EXIT() : base(OpCodes.OPCODE_DATA_LOBBY_GETSERVERS_EXIT_OK, new byte[] { 0x00, 0x00 }) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/MailBodyModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /FragmentNetslumServerLauncher/FragmentNetslumServerLauncher.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Enumerations/ServiceStatusEnum.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Enumerations 2 | { 3 | 4 | /// 5 | /// Defines the various states of execution that a service can be in 6 | /// 7 | public enum ServiceStatusEnum 8 | { 9 | /// 10 | /// The service is currently inactive awaiting activation 11 | /// 12 | Inactive, 13 | 14 | /// 15 | /// The service is currently active and running properly 16 | /// 17 | Active, 18 | 19 | /// 20 | /// The service has experienced an error of some sort and needs to be addressed 21 | /// 22 | Faulted 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/GuildItemShopModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class GuildItemShopModel 4 | { 5 | public virtual int ItemShopID { get; set; } 6 | 7 | 8 | public virtual int GuildID { get; set; } 9 | 10 | 11 | public virtual int ItemID { get; set; } 12 | 13 | 14 | public virtual int Quantity { get; set; } 15 | 16 | 17 | public virtual int GeneralPrice { get; set; } 18 | 19 | 20 | public virtual int MemberPrice { get; set; } 21 | 22 | 23 | public virtual bool AvailableForGeneral { get; set; } 24 | 25 | 26 | public virtual bool AvailableForMember { get; set; } 27 | 28 | public GuildItemShopModel() 29 | { 30 | ItemShopID = -1; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/NewsSectionModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/GuildRepositoryModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class GuildRepositoryModel 4 | { 5 | public virtual int GuildID { get; set; } 6 | 7 | 8 | public virtual byte[] GuildName { get; set; } 9 | 10 | 11 | public virtual byte[] GuildEmblem { get; set; } 12 | 13 | 14 | public virtual byte[] GuildComment { get; set; } 15 | 16 | 17 | public virtual string EstablishmentDate { get; set; } 18 | 19 | 20 | public virtual int MasterPlayerID { get; set; } 21 | 22 | 23 | public virtual int GoldCoin { get; set; } 24 | 25 | 26 | public virtual int SilverCoin { get; set; } 27 | 28 | 29 | public virtual int BronzeCoin { get; set; } 30 | 31 | 32 | public virtual int Gp { get; set; } 33 | } 34 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/Attributes/OpCodeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FragmentNetslumServer.Entities.Attributes 4 | { 5 | /// 6 | /// Defines a non-data based OpCode 7 | /// 8 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 9 | public class OpCodeAttribute : Attribute 10 | { 11 | 12 | /// 13 | /// Gets the OpCode this attribute is meant to represent 14 | /// 15 | public ushort OpCode { get; private set; } 16 | 17 | /// 18 | /// Creates a new instance of 19 | /// 20 | /// The OpCode to use for mapping 21 | public OpCodeAttribute(ushort opcode) => OpCode = opcode; 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Regular/OPCODE_KEY_EXCHANGE_ACKNOWLEDGMENT.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Regular 6 | { 7 | [OpCode(OpCodes.OPCODE_KEY_EXCHANGE_ACKNOWLEDGMENT)] 8 | public sealed class OPCODE_KEY_EXCHANGE_ACKNOWLEDGMENT : NoResponseOpCodeHandler 9 | { 10 | public override Task> HandleIncomingRequestAsync(RequestContent request) 11 | { 12 | request.Client.InitializeDecryptionKey(request.Client.from_key, true); 13 | request.Client.InitializeEncryptionKey(request.Client.to_key, true); 14 | return base.HandleIncomingRequestAsync(request); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FragmentNetslumServerPubSub/Ioc/Interfaces/IPublisher.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServerPubSub.Ioc.Interfaces 2 | { 3 | 4 | /// 5 | /// One part of the pub-sub model. Provides a meaningful definition for a publisher to notify 6 | /// subscribers that an event or action has occurred that they should be interested in 7 | /// 8 | public interface IPublisher 9 | { 10 | 11 | /// 12 | /// Publishes an object instance to all listeners. 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// If is a reference type, ALL subscribers (listeners) will receive the SAME instance 18 | /// 19 | void Publish(T data); 20 | 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IOpCodeHandler.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace FragmentNetslumServer.Services.Interfaces 6 | { 7 | 8 | /// 9 | /// Defines a lightweight interface who is responsible for handling incoming packet requests 10 | /// 11 | public interface IOpCodeHandler 12 | { 13 | 14 | /// 15 | /// Handles the incoming instance 16 | /// 17 | /// The incoming 18 | /// A promise to handle the packet asynchronously 19 | Task> HandleIncomingRequestAsync(RequestContent request); 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_RETURN_DESKTOP.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 7 | { 8 | [OpCodeData(OpCodes.OPCODE_DATA_RETURN_DESKTOP)] 9 | public sealed class OPCODE_DATA_RETURN_DESKTOP : SimpleResponseOpCodeHandler 10 | { 11 | public OPCODE_DATA_RETURN_DESKTOP() : base(OpCodes.OPCODE_DATA_RETURN_DESKTOP_OK, new byte[] { 0x00, 0x00 }) { } 12 | public override Task> HandleIncomingRequestAsync(RequestContent request) 13 | { 14 | DBAccess.getInstance().setPlayerAsOffline(request.Client._characterPlayerID); 15 | return base.HandleIncomingRequestAsync(request); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Controllers/RefreshNewsSection.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using FragmentNetslumServer.Services; 3 | using FragmentNetslumServer.Services.Interfaces; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace FragmentNetslumServerWebApi.Controllers; 8 | 9 | [ApiController] 10 | [Route("refreshNews")] 11 | public class RefreshNewsSection 12 | { 13 | private readonly ILogger _logger; 14 | private readonly INewsService _newsService; 15 | 16 | public RefreshNewsSection(ILogger logger , INewsService newsService) 17 | { 18 | _logger = logger; 19 | _newsService = newsService; 20 | } 21 | 22 | [HttpGet] 23 | public async Task Get() 24 | { 25 | await _newsService.RefreshNewsList(); 26 | 27 | 28 | return "News Section Refreshed"; 29 | } 30 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/Attributes/OpCodeDataAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FragmentNetslumServer.Entities.Attributes 4 | { 5 | 6 | /// 7 | /// Defines an OpCode that is explicitly intended for usage with the data OpCode (0x30) 8 | /// 9 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 10 | public sealed class OpCodeDataAttribute : OpCodeAttribute 11 | { 12 | 13 | /// 14 | /// Gets the data-based OpCode 15 | /// 16 | public ushort DataOpCode { get; private set; } 17 | 18 | /// 19 | /// Creates a new instance of 20 | /// 21 | /// The OpCode to use for mapping 22 | public OpCodeDataAttribute(ushort dataOpCode) : base(OpCodes.OPCODE_DATA) => DataOpCode = dataOpCode; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": false, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:36501", 8 | "sslPort": 44394 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "status", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "FragmentServerWV_WebApi": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "status", 24 | "applicationUrl": "http://localhost:5001", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/AreaServer/OPCODE_DATA_AS_UPDATE_USERNUM.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Threading.Tasks; 6 | using static FragmentNetslumServer.Services.Extensions; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.AreaServer 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_AS_UPDATE_USERNUM), Description("Updates how many players are currently on an Area Server")] 11 | public sealed class OPCODE_DATA_AS_UPDATE_USERNUM : NoResponseOpCodeHandler 12 | { 13 | public override Task> HandleIncomingRequestAsync(RequestContent request) 14 | { 15 | request.Client.as_usernum = swap16(BitConverter.ToUInt16(request.Data, 2)); 16 | return base.HandleIncomingRequestAsync(request); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Controllers/RefreshMOD.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Services; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace FragmentNetslumServerWebApi.Controllers 6 | { 7 | [ApiController] 8 | [Route("motd")] 9 | public class RefreshMod : ControllerBase 10 | { 11 | private readonly ILogger _logger; 12 | 13 | public RefreshMod(ILogger logger) 14 | { 15 | _logger = logger; 16 | } 17 | 18 | [HttpGet] 19 | public string Get() 20 | { 21 | DBAccess.getInstance().RefreshMessageOfTheDay(); 22 | 23 | 24 | return "Message Of the Day Refreshed"; 25 | } 26 | 27 | [HttpPut] 28 | public IActionResult Put(string motd) 29 | { 30 | DBAccess.getInstance().SetMessageOfDay(motd); 31 | return Ok(); 32 | } 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/BBS/OPCODE_DATA_BBS_POST.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using static FragmentNetslumServer.Services.Extensions; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.BBS 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_BBS_POST)] 11 | public sealed class OPCODE_DATA_BBS_POST : SimpleResponseOpCodeHandler 12 | { 13 | public OPCODE_DATA_BBS_POST() : base(0x7813, new byte[] { 0x00, 0x00 }) { } 14 | 15 | public override Task> HandleIncomingRequestAsync(RequestContent request) 16 | { 17 | var id = swap32(BitConverter.ToUInt32(request.Data, 0)); 18 | DBAccess.getInstance().CreateNewPost(request.Data, id); 19 | return base.HandleIncomingRequestAsync(request); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Lobby/OPCODE_DATA_LOBBY_CHATROOM_GETLIST.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Lobby 7 | { 8 | [OpCodeData(OpCodes.OPCODE_DATA_LOBBY_CHATROOM_GETLIST)] 9 | public sealed class OPCODE_DATA_LOBBY_CHATROOM_GETLIST : IOpCodeHandler 10 | { 11 | public Task> HandleIncomingRequestAsync(RequestContent request) => 12 | Task.FromResult>(new[] 13 | { 14 | request.CreateResponse(OpCodes.OPCODE_DATA_LOBBY_CHATROOM_CATEGORY, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }), 15 | request.CreateResponse(OpCodes.OPCODE_DATA_LOBBY_CHATROOM_CATEGORY, new byte[] { 0x00, 0x01, 0x00, 0x00 }) 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IBulletinBoardService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using FragmentNetslumServer.Models; 4 | 5 | namespace FragmentNetslumServer.Services.Interfaces 6 | { 7 | public interface IBulletinBoardService: IBaseService 8 | { 9 | 10 | Task> GetCategoriesAsync(); 11 | 12 | Task> GetThreadsAsync(int categoryId); 13 | 14 | Task> GetThreadDetailsAsync(int threadId); 15 | 16 | Task GetThreadPostContentAsync(int postId); 17 | 18 | 19 | 20 | Task ConvertCategoryToBytesAsync(BbsCategoryModel categoryModel); 21 | 22 | Task ConvertThreadToBytesAsync(BbsThreadModel threadModel); 23 | 24 | Task ConvertThreadDetailsToBytesAsync(BbsPostMetaModel postMetaModel); 25 | 26 | Task ConvertThreadPostToBytesAsync(BbsPostBody postBody); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/RankingDataModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class RankingDataModel 4 | { 5 | public virtual int id { get; set; } 6 | public virtual string antiCheatEngineResult {get; set; } 7 | public virtual string loginTime {get; set; } 8 | public virtual string diskID {get; set; } 9 | public virtual string saveID {get; set; } 10 | public virtual string characterSaveID {get; set; } 11 | public virtual string characterName {get; set; } 12 | public virtual int characterLevel {get; set; } 13 | public virtual string characterClassName {get; set; } 14 | public virtual int characterHP {get; set; } 15 | public virtual int characterSP {get; set; } 16 | public virtual int characterGP {get; set; } 17 | public virtual int godStatusCounterOnline {get; set; } 18 | public virtual int averageFieldLevel {get; set; } 19 | public virtual int accountID { get; set; } 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /settings.ini.example: -------------------------------------------------------------------------------- 1 | # Server Connection 2 | # 0.0.0.0 binds to any available interface 3 | ip = 0.0.0.0 4 | port = 49000 5 | 6 | # Database Connection 7 | dbhost = 127.0.0.1 8 | dbport = 3306 9 | dbname = fragment_schema 10 | dbuser = root 11 | dbpass = root 12 | 13 | # "is alive"-ping delay in ms 14 | # The lower this is, the more active the server is. 15 | # However, the lower this is, the faster a client 16 | # that has disconnected will be removed from the 17 | # server 18 | ping = 5000 19 | 20 | # Log settings 21 | # Setup the sinks in a CSV related variable 22 | # Valid entries are: console,file 23 | sinks = console,file 24 | folder = logs/ 25 | logsize = 100000 26 | # Possible options: Verbose, Debug, Information, 27 | # Warning, Error, Fatal 28 | # This value is case sensitive 29 | lobbyloglevel = Information 30 | apiloglevel = Warning 31 | 32 | # Tick rate, in milliseconds. This is 33 | # how often the server checks for client data 34 | # Recommended Value: 30; any higher will cause 35 | # delays in responding to the client 36 | tick = 30 -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/BbsPostMetaModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/MailMetaModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Controllers/DebugController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace FragmentNetslumServerWebApi.Controllers 7 | { 8 | 9 | [ApiController] 10 | [Route("debug")] 11 | public class DebugController : ControllerBase 12 | { 13 | private readonly ILogger logger; 14 | private readonly ILobbyChatService lobbyChatService; 15 | 16 | public DebugController( 17 | ILogger logger, 18 | ILobbyChatService lobbyChatService) 19 | { 20 | this.logger = logger; 21 | this.lobbyChatService = lobbyChatService; 22 | } 23 | 24 | 25 | [HttpGet] 26 | public async Task Get() 27 | { 28 | // foreach(var lobby in lobbyChatService.) 29 | await lobbyChatService.Main.SendServerMessageAsync("This is a test message from a WebAPI controller"); 30 | return Ok(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_DONATE_COINS.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 8 | { 9 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_DONATE_COINS)] 10 | public sealed class OPCODE_DATA_GUILD_DONATE_COINS : IOpCodeHandler 11 | { 12 | private readonly IGuildManagementService _guildManagementService; 13 | 14 | public OPCODE_DATA_GUILD_DONATE_COINS(IGuildManagementService guildManagementService) 15 | { 16 | _guildManagementService = guildManagementService; 17 | } 18 | 19 | public Task> HandleIncomingRequestAsync(RequestContent request) 20 | { 21 | return Task.FromResult>(new[] 22 | { request.CreateResponse(0x7701, _guildManagementService.DonateCoinsToGuild(request.Data)) }); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /FragmentNetslumServerPubSub/Ioc/Implementations/Subscriber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FragmentNetslumServerPubSub.Core; 3 | using FragmentNetslumServerPubSub.Ioc.Interfaces; 4 | 5 | namespace FragmentNetslumServerPubSub.Ioc.Implementations 6 | { 7 | 8 | public class Subscriber : ISubscriber 9 | { 10 | private readonly Hub hub; 11 | 12 | public Subscriber( Hub hub ) 13 | { 14 | this.hub = hub; 15 | } 16 | 17 | public bool Exists( object subscriber ) => hub.Exists( subscriber ); 18 | 19 | public bool Exists( object subscriber, Action handler ) => hub.Exists( subscriber, handler ); 20 | 21 | public void Subscribe( object subscriber, Action handler ) => hub.Subscribe( subscriber, handler ); 22 | 23 | public void Unsubscribe( object subscriber ) => hub.Unsubscribe( subscriber ); 24 | 25 | public void Unsubscribe( object subscriber ) => hub.Unsubscribe( subscriber, (Action) null ); 26 | 27 | public void Unsubscribe( object subscriber, Action handler ) => hub.Unsubscribe( subscriber, handler ); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Mail/OPCODE_DATA_GUILD_MAIL_SEND.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Threading.Tasks; 5 | using FragmentNetslumServer.Entities.Attributes; 6 | using FragmentNetslumServer.Services.Interfaces; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Mail; 9 | 10 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_MAIL_SEND), Description("Send a mail to all the guild members")] 11 | public sealed class OPCODE_DATA_GUILD_MAIL_SEND : SimpleResponseOpCodeHandler 12 | { 13 | private readonly IMailService mailService; 14 | 15 | public OPCODE_DATA_GUILD_MAIL_SEND(IMailService mailService) : base(OpCodes.OPCODE_DATA_GUILD_MAIL_SEND_OK, new byte[] { 0x00, 0x00 }) 16 | { 17 | this.mailService = mailService ?? throw new ArgumentNullException(nameof(mailService)); 18 | } 19 | public override async Task> HandleIncomingRequestAsync(RequestContent request) 20 | { 21 | await mailService.SaveGuildMailAsync(request.Data); 22 | return await base.HandleIncomingRequestAsync(request); 23 | } 24 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_DISSOLVED.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 7 | { 8 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_DISSOLVED)] 9 | public sealed class OPCODE_DATA_GUILD_DISSOLVED : IOpCodeHandler 10 | { 11 | private readonly IGuildManagementService guildManagementService; 12 | 13 | public OPCODE_DATA_GUILD_DISSOLVED(IGuildManagementService guildManagementService) 14 | { 15 | this.guildManagementService = guildManagementService; 16 | } 17 | 18 | public Task> HandleIncomingRequestAsync(RequestContent request) 19 | { 20 | var responses = new List 21 | { 22 | request.CreateResponse(0x761A, guildManagementService.DestroyGuild(request.Client._guildID)) 23 | }; 24 | return Task.FromResult>(responses); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Lobby/OPCODE_DATA_LOBBY_EVENT.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Lobby 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_LOBBY_EVENT)] 11 | public sealed class OPCODE_DATA_LOBBY_EVENT : NoResponseOpCodeHandler 12 | { 13 | private readonly ILobbyChatService _lobbyChatService; 14 | 15 | public OPCODE_DATA_LOBBY_EVENT(ILobbyChatService lobbyChatService) 16 | { 17 | _lobbyChatService = lobbyChatService; 18 | } 19 | 20 | public override async Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | if (_lobbyChatService.TryFindLobby(request.Client, out var lcr)) 23 | { 24 | await lcr.SendPublicMessageAsync(request.Data, request.Client.ClientIndex); 25 | } 26 | return await base.HandleIncomingRequestAsync(request); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_BUY_ITEM.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services; 3 | using FragmentNetslumServer.Services.Interfaces; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 8 | { 9 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_BUY_ITEM)] 10 | public sealed class OPCODE_DATA_GUILD_BUY_ITEM : IOpCodeHandler 11 | { 12 | private readonly IGuildManagementService guildManagementService; 13 | 14 | public OPCODE_DATA_GUILD_BUY_ITEM(IGuildManagementService guildManagementService) 15 | { 16 | this.guildManagementService = guildManagementService; 17 | } 18 | 19 | public Task> HandleIncomingRequestAsync(RequestContent request) 20 | { 21 | var responses = new List 22 | { 23 | request.CreateResponse(0x770D, guildManagementService.BuyItemFromGuild(request.Data)) 24 | }; 25 | return Task.FromResult>(responses); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_GET_DONATION_SETTINGS.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 8 | { 9 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_GET_DONATION_SETTINGS)] 10 | public sealed class OPCODE_DATA_GUILD_GET_DONATION_SETTINGS : IOpCodeHandler 11 | { 12 | private readonly IGuildManagementService _guildManagementService; 13 | 14 | public OPCODE_DATA_GUILD_GET_DONATION_SETTINGS(IGuildManagementService guildManagementService) 15 | { 16 | _guildManagementService = guildManagementService; 17 | } 18 | 19 | public Task> HandleIncomingRequestAsync(RequestContent request) 20 | { 21 | return Task.FromResult>(new[] 22 | { 23 | request.CreateResponse(0x787a, 24 | _guildManagementService.GetItemDonationSettings(request.Client.isGuildMaster)) 25 | }); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_UPDATE_DETAILS.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 8 | { 9 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_UPDATE_DETAILS)] 10 | public sealed class OPCODE_DATA_GUILD_UPDATE_DETAILS : IOpCodeHandler 11 | { 12 | private readonly IGuildManagementService _guildManagementService; 13 | 14 | public OPCODE_DATA_GUILD_UPDATE_DETAILS(IGuildManagementService guildManagementService) 15 | { 16 | _guildManagementService = guildManagementService; 17 | 18 | } 19 | 20 | public Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | return Task.FromResult>(new[] 23 | { 24 | request.CreateResponse(0x761D, 25 | _guildManagementService.UpdateGuildEmblemComment(request.Data,request.Client._guildID)) 26 | }); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_LOGGEDIN_MEMBERS.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using static FragmentNetslumServer.Services.Extensions; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_LOGGEDIN_MEMBERS)] 11 | public sealed class OPCODE_DATA_GUILD_LOGGEDIN_MEMBERS : IOpCodeHandler 12 | { 13 | private readonly IGuildManagementService guildManagementService; 14 | 15 | public OPCODE_DATA_GUILD_LOGGEDIN_MEMBERS(IGuildManagementService guildManagementService) 16 | { 17 | this.guildManagementService = guildManagementService; 18 | } 19 | 20 | public Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | var guildId = swap16(BitConverter.ToUInt16(request.Data, 0)); 23 | return Task.FromResult>(new[] { request.CreateResponse(0x789d, guildManagementService.GetGuildInfo(guildId)) }); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_PLAYER_LEAVING.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_PLAYER_LEAVING)] 11 | public sealed class OPCODE_DATA_GUILD_PLAYER_LEAVING : IOpCodeHandler 12 | { 13 | 14 | private readonly IGuildManagementService _guildManagementService; 15 | 16 | public OPCODE_DATA_GUILD_PLAYER_LEAVING(IGuildManagementService guildManagementService) 17 | { 18 | _guildManagementService = guildManagementService; 19 | } 20 | 21 | public Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | return Task.FromResult>(new[] 24 | { 25 | request.CreateResponse(0x7617, 26 | _guildManagementService.LeaveGuild(request.Client._guildID, request.Client._characterPlayerID)) 27 | }); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/NewsSectionModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FragmentNetslumServer.Models 4 | { 5 | public class NewsSectionModel 6 | { 7 | public virtual ushort ArticleID { get; set; } 8 | public virtual string ArticleTitle { get; set; } 9 | public virtual string ArticleBody { get; set; } 10 | public virtual DateTime ArticleDate { get; set; } 11 | public virtual byte[] ArticleImage { get; set; } 12 | 13 | public virtual byte[] ArticleByteArray { get; set; } 14 | public virtual byte[] ImageSizeInfo { get; set; } 15 | public virtual byte[] ImageDetails { get; set; } 16 | 17 | public virtual NewsSectionModel Clone() 18 | { 19 | NewsSectionModel clone = new NewsSectionModel 20 | { 21 | ArticleID = this.ArticleID, 22 | ArticleTitle = this.ArticleTitle, 23 | ArticleBody = this.ArticleBody, 24 | ArticleDate = this.ArticleDate, 25 | ArticleImage = this.ArticleImage, 26 | ArticleByteArray = this.ArticleByteArray, 27 | ImageSizeInfo = this.ImageSizeInfo 28 | }; 29 | 30 | return clone; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Ranking/OPCODE_RANKING_VIEW_PLAYER.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using FragmentNetslumServer.Entities.Attributes; 5 | using FragmentNetslumServer.Services; 6 | using FragmentNetslumServer.Services.Interfaces; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Ranking 9 | { 10 | [OpCodeData(OpCodes.OPCODE_RANKING_VIEW_PLAYER)] 11 | public sealed class OPCODE_RANKING_VIEW_PLAYER : IOpCodeHandler 12 | { 13 | private readonly IRankingManagementService _rankingManagementService; 14 | 15 | public OPCODE_RANKING_VIEW_PLAYER(IRankingManagementService rankingManagementService) 16 | { 17 | _rankingManagementService = rankingManagementService; 18 | } 19 | 20 | public Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | uint rankPlayerID = BitConverter.ToUInt32(request.Data, 0).Swap(); 23 | ResponseContent response = request.CreateResponse(0x7839, _rankingManagementService.GetRankingPlayerInfo(rankPlayerID)); 24 | 25 | return Task.FromResult>(new [] {response}); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/SimpleResponseOpCodeHandler.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Services.Interfaces; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace FragmentNetslumServer.Entities.OpCodeHandlers 6 | { 7 | /// 8 | /// A base class that supports a single response of a predictable result to the client 9 | /// 10 | /// 11 | /// This is only useful when the response is deterministic. Thankfully, there are several OPCODES where the response is indeed deterministic 12 | /// 13 | public abstract class SimpleResponseOpCodeHandler : IOpCodeHandler 14 | { 15 | private readonly ushort responseOpCode; 16 | private readonly byte[] responseData; 17 | 18 | public SimpleResponseOpCodeHandler(ushort responseOpCode, byte[] responseData) 19 | { 20 | this.responseOpCode = responseOpCode; 21 | this.responseData = responseData; 22 | } 23 | 24 | public virtual Task> HandleIncomingRequestAsync(RequestContent request) => 25 | Task.FromResult>(new[] { request.CreateResponse(responseOpCode, responseData) }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_CREATE.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using static FragmentNetslumServer.Services.Extensions; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_CREATE)] 11 | public sealed class OPCODE_DATA_GUILD_CREATE : IOpCodeHandler 12 | { 13 | private readonly IGuildManagementService guildManagementService; 14 | 15 | public OPCODE_DATA_GUILD_CREATE(IGuildManagementService guildManagementService) 16 | { 17 | this.guildManagementService = guildManagementService; 18 | } 19 | 20 | public Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | var u = guildManagementService.CreateGuild(request.Data, request.Client._characterPlayerID); 23 | request.Client._guildID = u; 24 | request.Client.isGuildMaster = true; 25 | return Task.FromResult>(new[] { request.CreateResponse(0x7601, BitConverter.GetBytes(swap16(u))) }); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_UPDATEITEM_PRICING.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | using Serilog; 9 | 10 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 11 | { 12 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_UPDATEITEM_PRICING)] 13 | public sealed class OPCODE_DATA_GUILD_UPDATEITEM_PRICING : IOpCodeHandler 14 | { 15 | 16 | private readonly IGuildManagementService _guildManagementService; 17 | 18 | public OPCODE_DATA_GUILD_UPDATEITEM_PRICING(IGuildManagementService guildManagementService) 19 | { 20 | _guildManagementService = guildManagementService; 21 | 22 | } 23 | 24 | public Task> HandleIncomingRequestAsync(RequestContent request) 25 | { 26 | return Task.FromResult>(new[] 27 | { 28 | request.CreateResponse(0x7713, 29 | _guildManagementService.SetItemVisibilityAndPrice(request.Data)) 30 | }); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_0x788C.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 10 | { 11 | [OpCodeData(0x788C) , Description("Send a Direct message in the lobby ")] 12 | public sealed class OPCODE_DATA_0x788C : NoResponseOpCodeHandler 13 | { 14 | private readonly ILobbyChatService _lobbyChatService; 15 | public OPCODE_DATA_0x788C(ILobbyChatService lobbyChatService) 16 | { 17 | _lobbyChatService = lobbyChatService; 18 | } 19 | 20 | public override async Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | var destid = BitConverter.ToUInt16(request.Data, 2).Swap(); 23 | if (_lobbyChatService.TryFindLobby(request.Client, out var p)) 24 | { 25 | await p.SendDirectMessageAsync(request.Data, request.Client.ClientIndex, destid); 26 | } 27 | 28 | return await base.HandleIncomingRequestAsync(request); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_GET_INFO.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using static FragmentNetslumServer.Services.Extensions; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_GET_INFO)] 11 | public sealed class OPCODE_DATA_GUILD_GET_INFO : IOpCodeHandler 12 | { 13 | private readonly IGuildManagementService guildManagementService; 14 | 15 | public OPCODE_DATA_GUILD_GET_INFO(IGuildManagementService guildManagementService) 16 | { 17 | this.guildManagementService = guildManagementService; 18 | } 19 | 20 | public Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | var guildId = swap16(BitConverter.ToUInt16(request.Data, 0)); 23 | return Task.FromResult>( 24 | new[] 25 | { 26 | request.CreateResponse(OpCodes.OPCODE_DATA_GET_GUILD_INFO_RESPONSE, guildManagementService.GetGuildInfo(guildId)) 27 | }); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Mail/OPCODE_DATA_MAILCHECK.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using FragmentNetslumServer.Services; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Mail 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_MAILCHECK)] 11 | public sealed class OPCODE_DATA_MAILCHECK : IOpCodeHandler 12 | { 13 | public async Task> HandleIncomingRequestAsync(RequestContent request) 14 | { 15 | bool isNew = await Task.Run(() => 16 | DBAccess.getInstance().checkForNewMailByAccountID(Extensions.ReadAccountId(request.Data, 0))); 17 | ResponseContent responseContent; 18 | if (isNew) 19 | { 20 | responseContent = request.CreateResponse(OpCodes.OPCODE_DATA_MAILCHECK_OK, 21 | new byte[] { 0x00, 0x00, 0x01, 0x00 }); 22 | } 23 | else 24 | { 25 | responseContent = request.CreateResponse(OpCodes.OPCODE_DATA_MAILCHECK_OK, new byte[] { 0x00, 0x01 }); 26 | } 27 | 28 | return new[] { responseContent }; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Lobby/OPCODE_DATA_LOBBY_STATUS_UPDATE.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Threading.Tasks; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Lobby 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_LOBBY_STATUS_UPDATE), Description("Propagates updates from a Client to the entire Lobby")] 11 | public sealed class OPCODE_DATA_LOBBY_STATUS_UPDATE : NoResponseOpCodeHandler 12 | { 13 | private readonly ILobbyChatService lobbyChatService; 14 | 15 | public OPCODE_DATA_LOBBY_STATUS_UPDATE(ILobbyChatService lobbyChatService) 16 | { 17 | this.lobbyChatService = lobbyChatService ?? throw new ArgumentNullException(nameof(lobbyChatService)); 18 | } 19 | 20 | public override async Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | if (lobbyChatService.TryFindLobby(request.Client, out var rm)) 23 | { 24 | await rm.UpdateLobbyStatusAsync(request.Data, request.Client.ClientIndex); 25 | } 26 | return await base.HandleIncomingRequestAsync(request); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/CharacterRepositoryModel.cs: -------------------------------------------------------------------------------- 1 | namespace FragmentNetslumServer.Models 2 | { 3 | public class CharacterRepositoryModel 4 | { 5 | public virtual int PlayerID { get; set; } 6 | public virtual byte[] CharacterName { get; set; } 7 | public virtual int ClassID { get; set; } 8 | public virtual int CharacterLevel { get; set; } 9 | public virtual byte[] Greeting { get; set; } 10 | public virtual int GuildID { get; set; } 11 | public virtual int GuildMaster { get; set; } 12 | public virtual int ModelNumber { get; set; } 13 | public virtual bool OnlineStatus { get; set; } 14 | public virtual int accountID { get; set; } 15 | public virtual string characterSaveID { get; set; } 16 | 17 | public virtual int charHP { get; set; } 18 | public virtual int charSP { get; set; } 19 | public virtual int charGP { get; set; } 20 | public virtual int charOnlineGoat { get; set; } 21 | public virtual int charOfflineGoat { get; set; } 22 | public virtual int charGoldCoin { get; set; } 23 | public virtual int charSilverCoin { get; set; } 24 | public virtual int charBronzeCoin { get; set; } 25 | 26 | public CharacterRepositoryModel() 27 | { 28 | PlayerID = -1; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_PLAYER_KICKED.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_PLAYER_KICKED)] 12 | public sealed class OPCODE_DATA_GUILD_PLAYER_KICKED : IOpCodeHandler 13 | { 14 | 15 | private readonly IGuildManagementService _guildManagementService; 16 | 17 | public OPCODE_DATA_GUILD_PLAYER_KICKED(IGuildManagementService guildManagementService) 18 | { 19 | _guildManagementService = guildManagementService; 20 | } 21 | public Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | uint playerToKick = BitConverter.ToUInt32(request.Data, 0).Swap(); 24 | 25 | return Task.FromResult>(new[] 26 | { 27 | request.CreateResponse(0x7865, 28 | _guildManagementService.KickPlayerFromGuild(request.Client._guildID, playerToKick)) 29 | }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_VIEW.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_VIEW)] 12 | public sealed class OPCODE_DATA_GUILD_VIEW : IOpCodeHandler 13 | { 14 | 15 | private readonly IGuildManagementService _guildManagementService; 16 | 17 | public OPCODE_DATA_GUILD_VIEW(IGuildManagementService guildManagementService) 18 | { 19 | _guildManagementService = guildManagementService; 20 | 21 | } 22 | 23 | public Task> HandleIncomingRequestAsync(RequestContent request) 24 | { 25 | var u = BitConverter.ToUInt16(request.Data, 0).Swap(); 26 | request.Client.currentGuildInvitaionSelection = u; 27 | return Task.FromResult>(new[] 28 | { 29 | request.CreateResponse(0x772D, 30 | _guildManagementService.GetGuildInfo(u)) 31 | }); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | 7 | namespace FragmentNetslumServerWebApi 8 | { 9 | public class Startup 10 | { 11 | public Startup(IConfiguration configuration) 12 | { 13 | Configuration = configuration; 14 | } 15 | 16 | public IConfiguration Configuration { get; } 17 | 18 | // This method gets called by the runtime. Use this method to add services to the container. 19 | public void ConfigureServices(IServiceCollection services) 20 | { 21 | services.AddControllers(); 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | //app.UseHttpsRedirection(); 33 | 34 | app.UseRouting(); 35 | 36 | //app.UseAuthorization(); 37 | 38 | app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/AreaServer/OPCODE_DATA_AS_UPDATE_STATUS.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using FragmentNetslumServer.Entities.Attributes; 5 | using static FragmentNetslumServer.Services.Extensions; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.AreaServer 8 | { 9 | [OpCodeData(OpCodes.OPCODE_DATA_AS_UPDATE_STATUS)] 10 | public sealed class OPCODE_DATA_AS_UPDATE_STATUS : NoResponseOpCodeHandler 11 | { 12 | public override Task> HandleIncomingRequestAsync(RequestContent request) 13 | { 14 | request.Client.publish_data_2 = request.Data; 15 | ExtractAreaServerData(request); 16 | return base.HandleIncomingRequestAsync(request); 17 | } 18 | 19 | private void ExtractAreaServerData(RequestContent request) 20 | { 21 | var data = request.Data; 22 | var client = request.Client; 23 | int pos = 67; // isn't this interesting 24 | client.areaServerName = ReadByteString(data, pos); 25 | pos += client.areaServerName.Length; 26 | client.areaServerLevel = swap16(BitConverter.ToUInt16(data, pos)); 27 | pos += 4; 28 | client.areaServerStatus = data[pos++]; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_GM_LEAVING.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_GM_LEAVING)] 12 | public sealed class OPCODE_DATA_GUILD_GM_LEAVING : IOpCodeHandler 13 | { 14 | 15 | private readonly IGuildManagementService _guildManagementService; 16 | 17 | public OPCODE_DATA_GUILD_GM_LEAVING(IGuildManagementService guildManagementService) 18 | { 19 | _guildManagementService = guildManagementService; 20 | } 21 | public Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | uint assigningPlayerID = BitConverter.ToUInt32(request.Data, 0).Swap(); 24 | 25 | return Task.FromResult>(new[] 26 | { 27 | request.CreateResponse(0x788E, 28 | _guildManagementService.LeaveGuildAndAssignMaster(request.Client._guildID, assigningPlayerID)) 29 | }); 30 | 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Mail/OPCODE_DATA_MAIL_SEND.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Threading.Tasks; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Mail 9 | { 10 | 11 | [OpCodeData(OpCodes.OPCODE_DATA_MAIL_SEND), Description("Sends mail from one player to another")] 12 | public sealed class OPCODE_DATA_MAIL_SEND : SimpleResponseOpCodeHandler 13 | { 14 | private readonly IMailService mailService; 15 | 16 | public OPCODE_DATA_MAIL_SEND(IMailService mailService) : base(OpCodes.OPCODE_DATA_MAIL_SEND_OK, new byte[] { 0x00, 0x00 }) 17 | { 18 | this.mailService = mailService ?? throw new ArgumentNullException(nameof(mailService)); 19 | } 20 | 21 | public override async Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | // Do I need to do this still??? 24 | //var buffer = new byte[4096]; 25 | //while (ns.DataAvailable) await ns.ReadAsync(buffer, 0, buffer.Length); 26 | await mailService.SaveMailAsync(request.Data); 27 | return await base.HandleIncomingRequestAsync(request); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Lobby/OPCODE_DATA_LOBBY_EXITROOM.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Threading.Tasks; 6 | 7 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Lobby 8 | { 9 | [OpCodeData(OpCodes.OPCODE_DATA_LOBBY_EXITROOM), Description("Announces to the client's current Lobby that it is leaving")] 10 | public sealed class OPCODE_DATA_LOBBY_EXITROOM : SimpleResponseOpCodeHandler 11 | { 12 | private readonly ILobbyChatService lobbyChatService; 13 | 14 | public OPCODE_DATA_LOBBY_EXITROOM(ILobbyChatService lobbyChatService) : base(OpCodes.OPCODE_DATA_LOBBY_EXITROOM_OK, new byte[] { 0x00, 0x00 }) 15 | { 16 | this.lobbyChatService = lobbyChatService ?? throw new System.ArgumentNullException(nameof(lobbyChatService)); 17 | } 18 | 19 | public override async Task> HandleIncomingRequestAsync(RequestContent request) 20 | { 21 | if (lobbyChatService.TryFindLobby(request.Client, out var lobby)) 22 | { 23 | await lobbyChatService.AnnounceRoomDeparture(lobby, (uint)request.Client.ClientIndex); 24 | } 25 | return await base.HandleIncomingRequestAsync(request); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Mail/OPCODE_DATA_MAIL_GET_MAIL_BODY.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Threading.Tasks; 7 | using static FragmentNetslumServer.Services.Extensions; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Mail 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_MAIL_GET_MAIL_BODY), Description("Returns the full message body for the specified mail")] 12 | public sealed class OPCODE_DATA_MAIL_GET_MAIL_BODY : IOpCodeHandler 13 | { 14 | private readonly IMailService mailService; 15 | 16 | public OPCODE_DATA_MAIL_GET_MAIL_BODY(IMailService mailService) 17 | { 18 | this.mailService = mailService ?? throw new ArgumentNullException(nameof(mailService)); 19 | } 20 | 21 | public async Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | var mailId = (int)swap32(BitConverter.ToUInt32(request.Data, 4)); 24 | var messageBodyModel = await mailService.GetMailContent(mailId); 25 | var messageBody = await mailService.ConvertMailBodyIntoBytes(messageBodyModel); 26 | return new[] { request.CreateResponse(OpCodes.OPCODE_DATA_MAIL_GET_MAIL_BODY_RESPONSE, messageBody) }; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_ACCEPT_GUILD_INVITE.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services; 3 | using FragmentNetslumServer.Services.Interfaces; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Threading.Tasks; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_ACCEPT_GUILD_INVITE)] 11 | public sealed class OPCODE_DATA_ACCEPT_GUILD_INVITE : IOpCodeHandler 12 | { 13 | public async Task> HandleIncomingRequestAsync(RequestContent request) 14 | { 15 | var responses = new List(); 16 | var ms = new MemoryStream(); 17 | await ms.WriteAsync(new byte[] { 0x76, 0x0B}); 18 | 19 | if (request.Data[1] == 0x08) //accepted the invitation 20 | { 21 | DBAccess.getInstance().EnrollPlayerInGuild(request.Client.currentGuildInvitaionSelection, request.Client._characterPlayerID, false); 22 | responses.Add(request.CreateResponse(0x760A, ms.ToArray())); // send guild ID 23 | } 24 | else 25 | { 26 | // rejected 27 | responses.Add(request.CreateResponse(0x760A, ms.ToArray())); // send guild ID 28 | } 29 | return responses; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_DONATE_ITEM.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_DONATE_ITEM)] 12 | public sealed class OPCODE_DATA_GUILD_DONATE_ITEM : IOpCodeHandler 13 | { 14 | private readonly IGuildManagementService _guildManagementService; 15 | 16 | public OPCODE_DATA_GUILD_DONATE_ITEM(IGuildManagementService guildManagementService) 17 | { 18 | _guildManagementService = guildManagementService; 19 | } 20 | 21 | public Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | request.Client._itemDontationID = BitConverter.ToUInt32(request.Data, 2).Swap(); 24 | request.Client._itemDonationQuantity = BitConverter.ToUInt16(request.Data, 6).Swap(); 25 | 26 | return Task.FromResult>(new [] {request.CreateResponse(0x7704, 27 | _guildManagementService.GetPriceOfItemToBeDonated(request.Client._guildID, 28 | request.Client._itemDontationID))}); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/BBS/OPCODE_DATA_BBS_THREAD_GET_CONTENT.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using static FragmentNetslumServer.Services.Extensions; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.BBS 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_BBS_THREAD_GET_CONTENT)] 11 | public sealed class OPCODE_DATA_BBS_THREAD_GET_CONTENT : IOpCodeHandler 12 | { 13 | private readonly IBulletinBoardService bulletinBoardService; 14 | 15 | public OPCODE_DATA_BBS_THREAD_GET_CONTENT(IBulletinBoardService bulletinBoardService) 16 | { 17 | this.bulletinBoardService = bulletinBoardService ?? throw new ArgumentNullException(nameof(bulletinBoardService)); 18 | } 19 | 20 | public async Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | var responses = new List(); 23 | var q = swap32(BitConverter.ToUInt32(request.Data, 4)); 24 | var postID = Convert.ToInt32(q); 25 | var bbsPostBody = await bulletinBoardService.GetThreadPostContentAsync(postID); 26 | var bbsPostData = await bulletinBoardService.ConvertThreadPostToBytesAsync(bbsPostBody); 27 | responses.Add(request.CreateResponse(0x781d, bbsPostData)); 28 | return responses; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IOpCodeProviderService.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace FragmentNetslumServer.Services.Interfaces 7 | { 8 | 9 | /// 10 | /// A service provider that's responsible for the discovery and management of the various instances 11 | /// 12 | public interface IOpCodeProviderService : IBaseService 13 | { 14 | 15 | /// 16 | /// Gets a collection of s but as their defined type 17 | /// 18 | IReadOnlyCollection Handlers { get; } 19 | 20 | /// 21 | /// Handles processing the incoming 22 | /// 23 | /// The that submitted the request 24 | /// The to handle 25 | Task> HandlePacketAsync(GameClientAsync gameClient, PacketAsync packet); 26 | 27 | /// 28 | /// Determines whether or not can currently handle this 29 | /// 30 | /// 31 | /// True if possible 32 | bool CanHandleRequest(PacketAsync packet); 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/News/OPCODE_DATA_NEWCHECK.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using FragmentNetslumServer.Entities.Attributes; 6 | using FragmentNetslumServer.Services.Interfaces; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.News 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_NEWCHECK) , Description("Check if there's new Articles to read")] 11 | public sealed class OPCODE_DATA_NEWCHECK : IOpCodeHandler 12 | { 13 | private readonly INewsService _newsService; 14 | private readonly Encoding _encoding; 15 | public OPCODE_DATA_NEWCHECK(INewsService newsService) 16 | { 17 | _newsService = newsService; 18 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 19 | _encoding = Encoding.GetEncoding("Shift-JIS"); 20 | } 21 | 22 | public async Task> HandleIncomingRequestAsync(RequestContent request) 23 | { 24 | bool isNew = await _newsService.CheckIfNewNewsForSaveId(_encoding.GetString(request.Client.save_id)); 25 | 26 | if (isNew) 27 | { 28 | return new[] { request.CreateResponse(OpCodes.OPCODE_DATA_NEWCHECK_OK, new byte[] { 0x00, 0x01 }) }; // send the new flag 29 | } 30 | else 31 | { 32 | return new[] { request.CreateResponse(OpCodes.OPCODE_DATA_NEWCHECK_OK, new byte[] { 0x00, 0x00 }) }; // there are no new articles to read 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/RankingDataModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_LOGON.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using Serilog; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_LOGON)] 11 | public sealed class OPCODE_DATA_LOGON : IOpCodeHandler 12 | { 13 | private readonly ILogger _logger; 14 | public OPCODE_DATA_LOGON(ILogger logger) 15 | { 16 | _logger = logger; 17 | } 18 | 19 | public Task> HandleIncomingRequestAsync(RequestContent request) 20 | { 21 | 22 | if (request.Data[1] == OpCodes.OPCODE_DATA_SERVERKEY_CHANGE) 23 | { 24 | _logger.Information("Client #{@clientIndex} has identified itself as an Area Server", request.Client.ClientIndex); 25 | request.Client.isAreaServer = true; 26 | return Task.FromResult>(new[] { request.CreateResponse(OpCodes.OPCODE_DATA_AREASERVER_OK, new byte[] { 0xDE, 0xAD }) }); 27 | 28 | } 29 | else 30 | { 31 | _logger.Information("Client #{@clientIndex} has identified itself as a Game Client (PS2 / PCSX2)", request.Client.ClientIndex); 32 | return Task.FromResult>(new[] { request.CreateResponse(OpCodes.OPCODE_DATA_LOGON_RESPONSE, new byte[] { 0x74, 0x32 }) }); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/GuildItemShopModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_GETITEMS.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_GETITEMS)] 12 | public sealed class OPCODE_DATA_GUILD_GETITEMS : IOpCodeHandler 13 | { 14 | private readonly IGuildManagementService _guildManagementService; 15 | 16 | public OPCODE_DATA_GUILD_GETITEMS(IGuildManagementService guildManagementService) 17 | { 18 | _guildManagementService = guildManagementService; 19 | } 20 | 21 | public Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | List responseContents = new List(); 24 | 25 | var u = BitConverter.ToUInt16(request.Data, 0).Swap(); 26 | 27 | List allGuildItems = _guildManagementService.GetAllGuildItemsWithSettings(u); 28 | 29 | responseContents.Add(request.CreateResponse(0x7729, 30 | BitConverter.GetBytes(((ushort)allGuildItems.Count).Swap()))); // number of items 31 | 32 | foreach (var item in allGuildItems) 33 | { 34 | responseContents.Add(request.CreateResponse(0x772A, item)); 35 | } 36 | 37 | return Task.FromResult>(responseContents); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_GETITEMS_TOBUY.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using FragmentNetslumServer.Services; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_GETITEMS_TOBUY)] 11 | public sealed class OPCODE_DATA_GUILD_GETITEMS_TOBUY : IOpCodeHandler 12 | { 13 | 14 | private readonly IGuildManagementService _guildManagementService; 15 | 16 | public OPCODE_DATA_GUILD_GETITEMS_TOBUY(IGuildManagementService guildManagementService) 17 | { 18 | _guildManagementService = guildManagementService; 19 | } 20 | 21 | public Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | List responseContents = new List(); 24 | 25 | var u = BitConverter.ToUInt16(request.Data, 0).Swap(); 26 | List membersItemList = _guildManagementService.GetGuildItems(u, false); 27 | 28 | responseContents.Add(request.CreateResponse(0x7709, 29 | BitConverter.GetBytes(((ushort)membersItemList.Count).Swap()))); // number of items 30 | 31 | foreach (var item in membersItemList) 32 | { 33 | responseContents.Add(request.CreateResponse(0x770a, item)); 34 | } 35 | 36 | return Task.FromResult>(responseContents); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_TAKE_GP.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | using Serilog; 9 | 10 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 11 | { 12 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_TAKE_GP)] 13 | public sealed class OPCODE_DATA_GUILD_TAKE_GP : IOpCodeHandler 14 | { 15 | private readonly ILogger _logger; 16 | private readonly IGuildManagementService _guildManagementService; 17 | 18 | public OPCODE_DATA_GUILD_TAKE_GP(ILogger logger,IGuildManagementService guildManagementService) 19 | { 20 | _logger = logger; 21 | _guildManagementService = guildManagementService; 22 | 23 | } 24 | 25 | public Task> HandleIncomingRequestAsync(RequestContent request) 26 | { 27 | ushort guildIDTakeMoney = BitConverter.ToUInt16(request.Data, 0).Swap(); 28 | uint amountOfMoneyToTakeOut = BitConverter.ToUInt32(request.Data, 2).Swap(); 29 | 30 | _logger.Debug("Guild ID {guildIDTakeMoney} \nAmount of money to Take out {amountOfMoneyToTakeOut}",guildIDTakeMoney,amountOfMoneyToTakeOut); 31 | return Task.FromResult>(new[] 32 | { 33 | request.CreateResponse(0x770F, 34 | _guildManagementService.TakeMoneyFromGuild(guildIDTakeMoney, amountOfMoneyToTakeOut)) 35 | }); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_SAVEID.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services; 3 | using FragmentNetslumServer.Services.Interfaces; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.IO; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using static FragmentNetslumServer.Services.Extensions; 11 | 12 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 13 | { 14 | [OpCodeData(OpCodes.OPCODE_DATA_SAVEID), Description("Associates a GameClient with an Account ID and loads out the MOTD")] 15 | public sealed class OPCODE_DATA_SAVEID : IOpCodeHandler 16 | { 17 | public async Task> HandleIncomingRequestAsync(RequestContent request) 18 | { 19 | var encoding = Encoding.GetEncoding("Shift-JIS"); 20 | MemoryStream m; 21 | byte[] saveID = ReadByteString(request.Data, 0); 22 | request.Client.save_id = saveID; 23 | m = new MemoryStream(); 24 | request.Client.AccountId = DBAccess.getInstance().GetPlayerAccountId(encoding.GetString(saveID)); 25 | uint swapped = swap32((uint)request.Client.AccountId); 26 | await m.WriteAsync(BitConverter.GetBytes(swapped), 0, 4); 27 | byte[] buff = encoding.GetBytes(DBAccess.getInstance().MessageOfTheDay); 28 | m.WriteByte((byte)(buff.Length - 1)); 29 | await m.WriteAsync(buff, 0, buff.Length); 30 | while (m.Length < 0x200) m.WriteByte(0); 31 | byte[] response = m.ToArray(); 32 | return new[] { request.CreateResponse(0x742A, response) }; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Exceptions/LobbyEmuCrashException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace FragmentNetslumServer.Exceptions 5 | { 6 | [Serializable(), Obsolete("Don't use this class please, thank you", true)] 7 | public class LobbyEmuCrashException : System.Exception 8 | { 9 | public LobbyEmuCrashException() : base() { } 10 | public LobbyEmuCrashException(string message) : base(message) { } 11 | public LobbyEmuCrashException(string message, System.Exception inner) : base(message, inner) { } 12 | 13 | // :( 14 | public LobbyEmuCrashException(string message, Thread t, System.Exception inner) : base(message, inner) 15 | { 16 | //Console.WriteLine("Lobby Emulator Crashed"); 17 | 18 | //if (t.IsAlive) 19 | //{ 20 | // t.Abort(); 21 | //} 22 | 23 | //foreach (GameClient client in Server.Instance.clients) 24 | // if (!client._exited) 25 | // client.Exit(); 26 | //foreach (ProxyClient client in Server.Instance.proxies) 27 | // if (!client._exited) 28 | // client.Exit(); 29 | 30 | //Log.Writeline("Server exited"); 31 | 32 | //Console.WriteLine("Restarting the Lobby Emulator "); 33 | 34 | //Server.Instance.Start(); 35 | } 36 | 37 | // A constructor is needed for serialization when an 38 | // exception propagates from a remoting server to the client. 39 | protected LobbyEmuCrashException(System.Runtime.Serialization.SerializationInfo info, 40 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { } 41 | } 42 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_INVITE_TO_GUILD.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_INVITE_TO_GUILD)] 12 | public sealed class OPCODE_DATA_INVITE_TO_GUILD : IOpCodeHandler 13 | { 14 | 15 | private readonly ILobbyChatService _lobbyChatService; 16 | 17 | public OPCODE_DATA_INVITE_TO_GUILD(ILobbyChatService lobbyChatService) 18 | { 19 | _lobbyChatService = lobbyChatService; 20 | 21 | } 22 | public async Task> HandleIncomingRequestAsync(RequestContent request) 23 | { 24 | var u = BitConverter.ToUInt16(request.Data, 0).Swap(); 25 | // This is probably only possible in the MAIN lobby so 26 | if (_lobbyChatService.TryFindLobby(request.Client, out var lobby)) 27 | { 28 | await lobby.InviteClientToGuildAsync(request.Data, request.Client.ClientIndex, u, request.Client._guildID); 29 | 30 | 31 | return new[] 32 | { 33 | request.CreateResponse(0x772D, new byte[]{0x00 ,0x00}) 34 | };//send to confirm that the player accepted the invite 35 | 36 | } 37 | return new[] 38 | { 39 | ResponseContent.Empty 40 | };// failed to find lobby ??? 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_GET_LIST_OF_ITEMS.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using static FragmentNetslumServer.Services.Extensions; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_GET_LIST_OF_ITEMS)] 11 | public sealed class OPCODE_DATA_GUILD_GET_LIST_OF_ITEMS : IOpCodeHandler 12 | { 13 | private readonly IGuildManagementService guildManagementService; 14 | 15 | public OPCODE_DATA_GUILD_GET_LIST_OF_ITEMS(IGuildManagementService guildManagementService) 16 | { 17 | this.guildManagementService = guildManagementService; 18 | } 19 | 20 | public Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | var responses = new List(); 23 | var guildId = swap16(BitConverter.ToUInt16(request.Data, 0)); 24 | bool isGeneral = guildId != request.Client._guildID; 25 | 26 | var listOfItemsForGeneralStore = guildManagementService.GetGuildItems(guildId, isGeneral); 27 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_GUILD_ITEMS_COUNT, BitConverter.GetBytes(swap16((ushort)listOfItemsForGeneralStore.Count)))); 28 | 29 | foreach (var item in listOfItemsForGeneralStore) 30 | { 31 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_GUILD_ITEM_DETAILS, item)); 32 | } 33 | 34 | return Task.FromResult>(responses); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IGuildManagementService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace FragmentNetslumServer.Services.Interfaces 4 | { 5 | public interface IGuildManagementService : IBaseService 6 | { 7 | byte[] AddItemToGuildInventory(ushort guildID, uint itemID, ushort itemQuantity, uint generalPrice, uint memberPrice, bool isGeneral, bool isMember, bool isGuildMaster); 8 | byte[] BuyItemFromGuild(byte[] argument); 9 | ushort CreateGuild(byte[] argument, uint masterPlayerID); 10 | byte[] DestroyGuild(ushort guildID); 11 | byte[] DonateCoinsToGuild(byte[] argument); 12 | List GetAllGuildItemsWithSettings(ushort guildID); 13 | byte[] GetGuildInfo(ushort guildID); 14 | List GetGuildItems(ushort guildId, bool isGeneral); 15 | List GetGuildMembersListByClass(ushort guildID, ushort categoryID, uint playerID); 16 | byte[] GetItemDonationSettings(bool isMaster); 17 | List GetListOfGuilds(); 18 | byte[] GetPlayerGuild(uint characterID); 19 | byte[] GetPriceOfItemToBeDonated(ushort guildID, uint itemID); 20 | byte[] KickPlayerFromGuild(ushort guildID, uint playerToKick); 21 | byte[] LeaveGuild(ushort guildID, uint characterID); 22 | byte[] LeaveGuildAndAssignMaster(ushort guildID, uint playerToAssign); 23 | byte[] ReadByteGuildEmblem(byte[] data, int pos); 24 | byte[] ReadByteString(byte[] data, int pos); 25 | byte[] SetItemVisibilityAndPrice(byte[] argument); 26 | byte[] TakeItemFromGuild(ushort guildID, uint itemID, ushort quantity); 27 | byte[] TakeMoneyFromGuild(ushort guildID, uint amountOfMoney); 28 | byte[] UpdateGuildEmblemComment(byte[] argument, ushort guildID); 29 | } 30 | } -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Models/AreaServerModel.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using FragmentNetslumServer.Entities; 3 | 4 | namespace FragmentNetslumServerWebApi.Models 5 | { 6 | public class AreaServerModel 7 | { 8 | private string _serverName; 9 | private int _serverLevel; 10 | private string _serverStatus; 11 | private int _numberOfPlayers; 12 | 13 | 14 | public static AreaServerModel ConvertDate(GameClientAsync client) 15 | { 16 | if (null == client.AreaServerName) 17 | return null; 18 | 19 | 20 | AreaServerModel model = new AreaServerModel(); 21 | 22 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 23 | 24 | model._serverName = Encoding.GetEncoding("Shift-JIS").GetString(client.AreaServerName,0,client.AreaServerName.Length-1); 25 | model._serverLevel = client.AreaServerLevel; 26 | model._serverStatus = client.AreaServerStatus == 0 ? "Available" : "Busy"; 27 | model._numberOfPlayers = client.Players; 28 | 29 | return model; 30 | } 31 | 32 | public string ServerName 33 | { 34 | get => _serverName; 35 | set => _serverName = value; 36 | } 37 | 38 | public int ServerLevel 39 | { 40 | get => _serverLevel; 41 | set => _serverLevel = value; 42 | } 43 | 44 | public string ServerStatus 45 | { 46 | get => _serverStatus; 47 | set => _serverStatus = value; 48 | } 49 | 50 | public int NumberOfPlayers 51 | { 52 | get => _numberOfPlayers; 53 | set => _numberOfPlayers = value; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/BBS/OPCODE_DATA_BBS_THREAD_GETMENU.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using static FragmentNetslumServer.Services.Extensions; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.BBS 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_BBS_THREAD_GETMENU)] 11 | public sealed class OPCODE_DATA_BBS_THREAD_GETMENU : IOpCodeHandler 12 | { 13 | private readonly IBulletinBoardService bulletinBoardService; 14 | 15 | public OPCODE_DATA_BBS_THREAD_GETMENU(IBulletinBoardService bulletinBoardService) 16 | { 17 | this.bulletinBoardService = bulletinBoardService ?? throw new ArgumentNullException(nameof(bulletinBoardService)); 18 | } 19 | 20 | public async Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | var responses = new List(); 23 | var i = swap32(BitConverter.ToUInt32(request.Data, 0)); 24 | var threadID = Convert.ToInt32(i); 25 | var postMetaList = await bulletinBoardService.GetThreadDetailsAsync(threadID); 26 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_BBS_THREAD_LIST, BitConverter.GetBytes(swap32((uint)postMetaList.Count)))); 27 | foreach (var meta in postMetaList) 28 | { 29 | var postMetaBytes = await bulletinBoardService.ConvertThreadDetailsToBytesAsync(meta); 30 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_BBS_ENTRY_POST_META, postMetaBytes)); 31 | } 32 | return responses; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/AreaServer/OPCODE_DATA_AS_PUBLISH_DETAILS.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Threading.Tasks; 5 | using FragmentNetslumServer.Entities.Attributes; 6 | using FragmentNetslumServer.Services.Interfaces; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.AreaServer 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS1), 11 | OpCodeData(OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS2)] 12 | class OPCODE_DATA_AS_PUBLISH_DETAILS : IOpCodeHandler 13 | { 14 | public async Task> HandleIncomingRequestAsync(RequestContent request) 15 | { 16 | switch(request.DataOpCode) 17 | { 18 | case OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS1: 19 | MemoryStream m; 20 | int end = request.Data.Length - 1; 21 | while (request.Data[end] == 0) end--; 22 | end++; 23 | m = new MemoryStream(); 24 | await m.WriteAsync(request.Data, 65, end - 65); 25 | request.Client.publish_data_1 = m.ToArray(); 26 | return new[] { request.CreateResponse(OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS1_OK, new byte[] { 0x00, 0x01 }) }; 27 | case OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS2: 28 | return new[] { request.CreateResponse(OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS2_OK, new byte[] { 0xDE, 0xAD }) }; 29 | } 30 | throw new ArgumentOutOfRangeException(nameof(request.DataOpCode), $"{request.DataOpCode:X2} is outside the expected values ({OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS1:X2} & {OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS2:X2})"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_TAKE_ITEM.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | using Serilog; 9 | 10 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 11 | { 12 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_TAKE_ITEM)] 13 | public sealed class OPCODE_DATA_GUILD_TAKE_ITEM : IOpCodeHandler 14 | { 15 | private readonly ILogger _logger; 16 | private readonly IGuildManagementService _guildManagementService; 17 | 18 | public OPCODE_DATA_GUILD_TAKE_ITEM(ILogger logger,IGuildManagementService guildManagementService) 19 | { 20 | _logger = logger; 21 | _guildManagementService = guildManagementService; 22 | 23 | } 24 | public Task> HandleIncomingRequestAsync(RequestContent request) 25 | { 26 | ushort guildIDTakeItem = BitConverter.ToUInt16(request.Data, 0).Swap(); 27 | uint itemIDToTakeOut = BitConverter.ToUInt32(request.Data, 2).Swap(); 28 | ushort quantityToTake = BitConverter.ToUInt16(request.Data, 6).Swap(); 29 | 30 | _logger.Debug("Guild ID {guildIDTakeItem}\nItem ID to take {itemIDToTakeOut}\n quantity to take out {quantityToTake}" ,guildIDTakeItem , itemIDToTakeOut,quantityToTake); 31 | 32 | return Task.FromResult>(new[] 33 | { 34 | request.CreateResponse(0x7711, 35 | _guildManagementService.TakeItemFromGuild(guildIDTakeItem, itemIDToTakeOut,quantityToTake)) 36 | }); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # .hack//frägment Server Emulator 2 | 3 | [![Build Status](https://app.travis-ci.com/Zackmon/FragmentNetslumServer.svg?branch=master)](https://app.travis-ci.com/Zackmon/FragmentNetslumServer) 4 | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Zackmon_FragmentServer_netCore&metric=alert_status)](https://sonarcloud.io/dashboard?id=Zackmon_FragmentServer_netCore) 5 | 6 | A private Lobby Server Emulator for the PS2 game .hack//frägment 7 | 8 | # Credits 9 | Big thanks to Warranty Voider for the original port of the C/C++ [Lobby Server](https://github.com/Lord-Ptolemy/lobbyemu). 10 | Lobby Server in action: https://www.youtube.com/watch?v=VErjuUM4AQM (Credit to Warranty Voider for the video) 11 | 12 | # Setup 13 | The Lobby Server requires a MySQL/MariaDB backend. The file `settings.ini.example` located in the root of this repository should be copied and renamed to `settings.ini`, then modified with the connection details for the database. 14 | 15 | ## Database Setup 16 | Once your configuration file has been adjusted, you will need to run `FragmentNetslumServer/SQL/DB.SQL` to lay out the correct schema objects. 17 | 18 | # Web Interface 19 | `FragmentNetslumServerLauncher` includes a reference to `FragmentNetslumServerWebAPI` and fires it up, attempting to expose all internal services to the WebAPI. For the time being, there is no proper UI but rather API calls. In the future, I hope to include a barebones Web UI that would allow for an Administrator to remotely control the system. 20 | 21 | # Notes 22 | There are plenty of things I'm considering doing with the code base. These are listed in no particular order: 23 | - Some additional refactoring / abstractions to properly handle Clients versus Area Servers 24 | - Consider a fully functional Web UI (complete with security abstractions) 25 | - Provide a consistent, fully documented, read only API 26 | - Figure out why Guild Chat doesn't work -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/GuildRepositoryModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Mail/OPCODE_DATA_MAIL_GET.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Threading.Tasks; 7 | using static FragmentNetslumServer.Services.Extensions; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Mail 10 | { 11 | 12 | [OpCodeData(OpCodes.OPCODE_DATA_MAIL_GET), Description("Retrieves mail for a requesting client")] 13 | public sealed class OPCODE_DATA_MAIL_GET : IOpCodeHandler 14 | { 15 | private readonly IMailService mailService; 16 | 17 | public OPCODE_DATA_MAIL_GET(IMailService mailService) 18 | { 19 | this.mailService = mailService ?? throw new ArgumentNullException(nameof(mailService)); 20 | } 21 | 22 | public async Task> HandleIncomingRequestAsync(RequestContent request) 23 | { 24 | var responses = new List(); 25 | var accountId = ReadAccountID(request.Data, 0); 26 | var mail = await mailService.GetMailAsync(accountId); 27 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_MAIL_GETOK, BitConverter.GetBytes(swap32((uint)mail.Count)))); 28 | foreach (var item in mail) 29 | { 30 | var mailContent = await mailService.ConvertMailMetaIntoBytes(item); 31 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_MAIL_GET_NEWMAIL_HEADER, mailContent)); 32 | } 33 | return responses; 34 | } 35 | 36 | static int ReadAccountID(byte[] data, int pos) 37 | { 38 | byte[] accountID = new byte[4]; 39 | Buffer.BlockCopy(data, pos, accountID, 0, 4); 40 | return (int)swap32(BitConverter.ToUInt32(accountID)); 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/AreaServer/OPCODE_DATA_AS_IPPORT.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using FragmentNetslumServer.Entities.Attributes; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.AreaServer 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_AS_IPPORT), Description("Determines the external IP address for the Client. This does also attempt to handle rewriting 127.0.0.1 to a 'more correct' IP address")] 11 | public sealed class OPCODE_DATA_AS_IPPORT : SimpleResponseOpCodeHandler 12 | { 13 | public OPCODE_DATA_AS_IPPORT() : base(OpCodes.OPCODE_DATA_AS_IPPORT_OK, new byte[] { 0x00, 0x00 }) { } 14 | 15 | public override Task> HandleIncomingRequestAsync(RequestContent request) 16 | { 17 | using (MemoryStream memoryStream = new MemoryStream()) 18 | { 19 | memoryStream.Write(request.Data); 20 | request.Client.ipdata = memoryStream.ToArray(); // local ip coming from Area Server 21 | } 22 | var externalIpAddress = request.Client.ipEndPoint.Address.ToString(); // Capturing the external IP from ipEndpoint 23 | if (externalIpAddress == Helpers.IPAddressHelpers.LOOPBACK_IP_ADDRESS) 24 | { 25 | externalIpAddress = Helpers.IPAddressHelpers.GetLocalIPAddress2(); 26 | } 27 | var ipAddress = externalIpAddress.Split('.'); 28 | // var ipAddressBytes = ipAddress.Reverse().Select(c => byte.Parse(c)).ToArray(); 29 | 30 | request.Data[3] = byte.Parse(ipAddress[0]); 31 | request.Data[2] = byte.Parse(ipAddress[1]); 32 | request.Data[1] = byte.Parse(ipAddress[2]); 33 | request.Data[0] = byte.Parse(ipAddress[3]); 34 | 35 | request.Client.externalIPAddress = request.Data; 36 | return base.HandleIncomingRequestAsync(request); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Regular/OPCODE_KEY_EXCHANGE_REQUEST.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.IO; 6 | using System.Security.Cryptography; 7 | using System.Threading.Tasks; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Regular 10 | { 11 | [OpCode(OpCodes.OPCODE_KEY_EXCHANGE_REQUEST), 12 | Description("Handles initializing encryption & decryption keys on the connected Client")] 13 | public sealed class OPCODE_KEY_EXCHANGE_REQUEST : IOpCodeHandler 14 | { 15 | public async Task> HandleIncomingRequestAsync(RequestContent request) 16 | { 17 | var responseStream = new MemoryStream(); 18 | responseStream.Write(request.Data, 4, 16); 19 | var from_key = responseStream.ToArray(); 20 | var to_key = new byte[16]; 21 | using (var rng = new RNGCryptoServiceProvider()) 22 | { 23 | rng.GetBytes(to_key); 24 | } 25 | await responseStream.DisposeAsync(); 26 | request.Client.InitializeDecryptionKey(from_key); 27 | request.Client.InitializeEncryptionKey(to_key); 28 | 29 | responseStream = new MemoryStream(); 30 | responseStream.WriteByte(0); 31 | responseStream.WriteByte(0x10); 32 | responseStream.Write(from_key, 0, 16); 33 | responseStream.WriteByte(0); 34 | responseStream.WriteByte(0x10); 35 | responseStream.Write(to_key, 0, 16); 36 | responseStream.Write(new byte[] { 0, 0, 0, 0xe, 0, 0, 0, 0, 0, 0 }, 0, 10); 37 | var responseArray = responseStream.ToArray(); 38 | var checksum = Crypto.Checksum(responseArray); 39 | await responseStream.DisposeAsync(); 40 | return new[] { new ResponseContent(request, OpCodes.OPCODE_KEY_EXCHANGE_RESPONSE, responseArray, checksum) }; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Controllers/StatusPageController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using FragmentNetslumServerWebApi.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace FragmentNetslumServerWebApi.Controllers 8 | { 9 | [ApiController] 10 | [Route("status")] 11 | public class StatusPageController : ControllerBase 12 | { 13 | private readonly ILogger _logger; 14 | private readonly IClientProviderService clientProviderService; 15 | private readonly IClientConnectionService clientConnectionService; 16 | 17 | public StatusPageController( 18 | ILogger logger, 19 | IClientProviderService clientProviderService, 20 | IClientConnectionService clientConnectionService) 21 | { 22 | _logger = logger ?? throw new ArgumentNullException(nameof(logger)); 23 | this.clientProviderService = clientProviderService ?? throw new ArgumentNullException(nameof(clientProviderService)); 24 | this.clientConnectionService = clientConnectionService ?? throw new ArgumentNullException(nameof(clientConnectionService)); 25 | } 26 | 27 | [HttpGet] 28 | public ClientsModel Get() 29 | { 30 | ClientsModel clientList = new ClientsModel(); 31 | foreach (var client in clientProviderService.Clients) 32 | { 33 | if (client.IsAreaServer) 34 | { 35 | AreaServerModel model = AreaServerModel.ConvertDate(client); 36 | if (model!= null) 37 | clientList._areaServerList.Add(model); 38 | } 39 | else 40 | { 41 | PlayerModel model = PlayerModel.ConvertData(client); 42 | if (model != null) 43 | clientList.PlayerList.Add(model); 44 | } 45 | } 46 | 47 | return clientList; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/News/OPCODE_DATA_NEWS_GETPOST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Entities.Attributes; 8 | using FragmentNetslumServer.Services; 9 | using FragmentNetslumServer.Services.Interfaces; 10 | 11 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.News; 12 | 13 | [OpCodeData(OpCodes.OPCODE_DATA_NEWS_GETPOST), Description("Get the image for the requested article")] 14 | public sealed class OPCODE_DATA_NEWS_GETPOST : IOpCodeHandler 15 | { 16 | private readonly INewsService _newsService; 17 | private readonly Encoding _encoding; 18 | 19 | public OPCODE_DATA_NEWS_GETPOST(INewsService newsService) 20 | { 21 | _newsService = newsService; 22 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 23 | _encoding = Encoding.GetEncoding("Shift-JIS"); 24 | 25 | } 26 | public async Task> HandleIncomingRequestAsync(RequestContent request) 27 | { 28 | List listOfResponse = new List(); 29 | 30 | var articleId = BitConverter.ToUInt16(request.Data, 0).Swap(); 31 | 32 | var article = (await _newsService.GetNewsArticles()).First(a => a.ArticleID == articleId); 33 | 34 | if (article.ImageSizeInfo == null || article.ImageDetails == null) 35 | { 36 | listOfResponse.Add(request.CreateResponse(0x7857, new byte[] {0x00,0x00 })); // Error while getting the image data 37 | } 38 | else 39 | { 40 | listOfResponse.Add(request.CreateResponse(0x7855, article.ImageSizeInfo)); // send the image size and chunk count 41 | listOfResponse.Add(request.CreateResponse(0x7856, article.ImageDetails)); // send the color pallets and the image indices 42 | } 43 | 44 | await _newsService.UpdateNewsLog(_encoding.GetString(request.Client.save_id), articleId); 45 | 46 | return listOfResponse; 47 | } 48 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_UPDATEITEM_PRICING_AVAILABILITY.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using FragmentNetslumServer.Services; 8 | using Serilog; 9 | 10 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 11 | { 12 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_UPDATEITEM_PRICING_AVAILABILITY)] 13 | public sealed class OPCODE_DATA_GUILD_UPDATEITEM_PRICING_AVAILABILITY : IOpCodeHandler 14 | { 15 | private readonly ILogger _logger; 16 | private readonly IGuildManagementService _guildManagementService; 17 | 18 | public OPCODE_DATA_GUILD_UPDATEITEM_PRICING_AVAILABILITY(ILogger logger,IGuildManagementService guildManagementService) 19 | { 20 | _logger = logger; 21 | _guildManagementService = guildManagementService; 22 | 23 | } 24 | public Task> HandleIncomingRequestAsync(RequestContent request) 25 | { 26 | uint generalPrice = BitConverter.ToUInt32(request.Data, 0).Swap(); 27 | uint memberPrice = BitConverter.ToUInt32(request.Data, 4).Swap(); 28 | bool isGeneral = BitConverter.ToBoolean(request.Data, 8); 29 | bool isMember = BitConverter.ToBoolean(request.Data, 9); 30 | 31 | _logger.Debug("GenePrice {GeneralPrice}\nMemberPrice {MemberPrice}\nisGeneral {isGeneral}\nisMember {isMember}",generalPrice,memberPrice,isGeneral,isMember); 32 | 33 | return Task.FromResult>(new[] 34 | { 35 | request.CreateResponse(0x7705, 36 | _guildManagementService.AddItemToGuildInventory( 37 | request.Client._guildID,request.Client._itemDontationID, 38 | request.Client._itemDonationQuantity, 39 | generalPrice,memberPrice,isGeneral,isMember,request.Client.isGuildMaster)) 40 | }); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_MEMBERLIST.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services; 3 | using FragmentNetslumServer.Services.Interfaces; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading.Tasks; 7 | using static FragmentNetslumServer.Services.Extensions; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_MEMBERLIST)] 12 | public sealed class OPCODE_DATA_GUILD_MEMBERLIST : IOpCodeHandler 13 | { 14 | private readonly IGuildManagementService guildManagementService; 15 | 16 | public OPCODE_DATA_GUILD_MEMBERLIST(IGuildManagementService guildManagementService) 17 | { 18 | this.guildManagementService = guildManagementService; 19 | } 20 | 21 | public Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | var responses = new List(); 24 | var u = swap16(BitConverter.ToUInt16(request.Data, 0)); 25 | if (u == 0)// Guild Member Category List 26 | { 27 | List listOfClasses = GetClassList(); 28 | responses.Add(request.CreateResponse(0x7611, BitConverter.GetBytes(swap16((ushort)listOfClasses.Count)))); 29 | foreach (var className in listOfClasses) 30 | { 31 | responses.Add(request.CreateResponse(0x7613, className)); 32 | } 33 | 34 | } 35 | else //MemberList in that Category 36 | { 37 | List memberList = guildManagementService.GetGuildMembersListByClass(request.Client._guildID, u, request.Client._characterPlayerID); 38 | responses.Add(request.CreateResponse(0x7614, BitConverter.GetBytes(swap16((ushort)memberList.Count)))); 39 | foreach (var member in memberList) 40 | { 41 | responses.Add(request.CreateResponse(0x7615, member)); 42 | } 43 | } 44 | return Task.FromResult>(responses); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IMailService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using FragmentNetslumServer.Models; 4 | 5 | namespace FragmentNetslumServer.Services.Interfaces 6 | { 7 | 8 | /// 9 | /// Defines a service for interacting with the mail 10 | /// 11 | public interface IMailService: IBaseService 12 | { 13 | 14 | /// 15 | /// Asynchronously saves (and subsequently sends) all Mail information to the database 16 | /// 17 | /// The mail content 18 | /// A promise to save the mail 19 | Task SaveMailAsync(byte[] content); 20 | 21 | Task SaveGuildMailAsync(byte[] content); 22 | 23 | /// 24 | /// Retrieves mail for the given account ID 25 | /// 26 | /// The player account ID 27 | /// A promise that, when awaited, will return a collection of 28 | Task> GetMailAsync(int accountId); 29 | 30 | /// 31 | /// Retrieves the message body for a given piece of mail 32 | /// 33 | /// The ID for the piece of mail 34 | /// 35 | Task GetMailContent(int mailId); 36 | 37 | /// 38 | /// Converts a received into a transmittable byte array 39 | /// 40 | /// 41 | /// A promise to convert the to a byte array 42 | Task ConvertMailMetaIntoBytes(MailMetaModel mail); 43 | 44 | /// 45 | /// Converts a received into a transmittable byte array 46 | /// 47 | /// 48 | /// A promise to convert the to a byte array 49 | Task ConvertMailBodyIntoBytes(MailBodyModel mail); 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_GET_ALL_GUILDS.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using static FragmentNetslumServer.Services.Extensions; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 9 | { 10 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_GET_ALL_GUILDS)] 11 | public sealed class OPCODE_DATA_GUILD_GET_ALL_GUILDS : IOpCodeHandler 12 | { 13 | private readonly IGuildManagementService guildManagementService; 14 | 15 | public OPCODE_DATA_GUILD_GET_ALL_GUILDS(IGuildManagementService guildManagementService) 16 | { 17 | this.guildManagementService = guildManagementService; 18 | } 19 | 20 | public Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | var responses = new List(); 23 | var u = swap16(BitConverter.ToUInt16(request.Data, 0)); 24 | // This is very similar to the area server handler 25 | // If this is zero, show the guild category breakdown (basically) 26 | // otherwise, show them all the guilds 27 | if (u == 0) 28 | { 29 | // Tell them we have ONE guild listing 30 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_GUILD_GROUP_COUNT, new byte[] { 0x00, 0x01 })); 31 | 32 | // This should print "ALL" on the game 33 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_GUILD_GROUP_CATEGORY, new byte[] { 0x00, 0x01, 0x41, 0x6c, 0x6c, 0x00 })); 34 | } 35 | else 36 | { 37 | var listOfGuilds = guildManagementService.GetListOfGuilds(); 38 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_GUILD_COUNT, BitConverter.GetBytes(swap16((ushort)listOfGuilds.Count)))); 39 | foreach (var guildName in listOfGuilds) 40 | { 41 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_GUILD_ENTRY, guildName)); 42 | } 43 | } 44 | return Task.FromResult>(responses); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Lobby/OPCODE_DATA_LOBBY_GETMENU.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | using static FragmentNetslumServer.Services.Extensions; 10 | 11 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Lobby 12 | { 13 | 14 | [OpCodeData(OpCodes.OPCODE_DATA_LOBBY_GETMENU), Description("Returns a list of available lobbies and participants")] 15 | public sealed class OPCODE_DATA_LOBBY_GETMENU : IOpCodeHandler 16 | { 17 | private readonly ILobbyChatService lobbyChatService; 18 | 19 | public OPCODE_DATA_LOBBY_GETMENU(ILobbyChatService lobbyChatService) 20 | { 21 | this.lobbyChatService = lobbyChatService ?? throw new System.ArgumentNullException(nameof(lobbyChatService)); 22 | } 23 | 24 | public async Task> HandleIncomingRequestAsync(RequestContent request) 25 | { 26 | var responses = new List(); 27 | var nonGuildLobbies = new List(lobbyChatService.Lobbies.Values.Where(c => c.Type == OpCodes.LOBBY_TYPE_MAIN)); 28 | 29 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_LOBBY_LOBBYLIST, BitConverter.GetBytes(swap16((ushort)nonGuildLobbies.Count)))); 30 | foreach (var room in nonGuildLobbies) 31 | { 32 | var m = new MemoryStream(); 33 | await m.WriteAsync(BitConverter.GetBytes(swap16(room.ID)), 0, 2); 34 | foreach (char c in room.Name) 35 | m.WriteByte((byte)c); 36 | m.WriteByte(0); 37 | await m.WriteAsync(BitConverter.GetBytes(swap16((ushort)room.Clients.Count)), 0, 2); 38 | await m.WriteAsync(BitConverter.GetBytes(swap16((ushort)(room.Clients.Count + 1))), 0, 2); 39 | // looks like some form of padding to align the message 40 | while (((m.Length + 2) % 8) != 0) m.WriteByte(0); 41 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_LOBBY_ENTRY_LOBBY, m.ToArray())); 42 | } 43 | 44 | return responses; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Config.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.IO; 5 | 6 | namespace FragmentNetslumServer 7 | { 8 | 9 | /// 10 | /// A simple key-value pair configuration class that also supports line comments 11 | /// 12 | /// 13 | /// INI lite 14 | /// 15 | public sealed class SimpleConfiguration 16 | { 17 | 18 | private readonly Dictionary configurationValues; 19 | 20 | 21 | /// 22 | /// Gets a that represents the loaded configuration 23 | /// 24 | public ReadOnlyDictionary Values => new ReadOnlyDictionary(configurationValues); 25 | 26 | /// 27 | /// Creates a new instance of the Configuration class 28 | /// 29 | public SimpleConfiguration() 30 | { 31 | configurationValues = new Dictionary(StringComparer.OrdinalIgnoreCase); 32 | if (File.Exists("settings.ini")) 33 | { 34 | var lines = File.ReadAllLines("settings.ini"); 35 | foreach (var line in lines) 36 | { 37 | var clean = line.Trim(); 38 | if (!string.IsNullOrWhiteSpace(clean) && !clean.StartsWith("#")) 39 | { 40 | var parts = line.Split('='); 41 | var key = parts[0].Trim(); 42 | var value = string.Join('=', parts[1..]).Trim(); 43 | configurationValues.Add(key.ToLowerInvariant(), value); 44 | } 45 | } 46 | 47 | } 48 | } 49 | 50 | /// 51 | /// Retrieves a value if it exists, otherwise returns 52 | /// 53 | /// The name of the configuration value 54 | /// The value to return if doesn't exist 55 | /// 56 | public string Get(string name, string @default = "") => configurationValues.ContainsKey(name) ? configurationValues[name] : @default; 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Guild/OPCODE_DATA_GUILD_GETMENU.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services; 3 | using FragmentNetslumServer.Services.Interfaces; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading.Tasks; 7 | using static FragmentNetslumServer.Services.Extensions; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Guild 10 | { 11 | /// 12 | /// Looks quite simliar to but uses different opcodes... 13 | /// 14 | [OpCodeData(OpCodes.OPCODE_DATA_GUILD_GETMENU)] 15 | public sealed class OPCODE_DATA_GUILD_GETMENU : IOpCodeHandler 16 | { 17 | private readonly IGuildManagementService guildManagementService; 18 | 19 | public OPCODE_DATA_GUILD_GETMENU(IGuildManagementService guildManagementService) 20 | { 21 | this.guildManagementService = guildManagementService; 22 | } 23 | 24 | public Task> HandleIncomingRequestAsync(RequestContent request) 25 | { 26 | var responses = new List(); 27 | var u = swap16(BitConverter.ToUInt16(request.Data, 0)); 28 | // This is very similar to the area server handler 29 | // If this is zero, show the guild category breakdown (basically) 30 | // otherwise, show them all the guilds 31 | if (u == 0) 32 | { 33 | // Tell them we have ONE guild listing 34 | responses.Add(request.CreateResponse(0x7734, new byte[] { 0x00, 0x01 })); 35 | 36 | // This should print "ALL" on the game 37 | responses.Add(request.CreateResponse(0x7736, new byte[] { 0x00, 0x01, 0x41, 0x6c, 0x6c, 0x00 })); 38 | } 39 | else 40 | { 41 | var listOfGuilds = guildManagementService.GetListOfGuilds(); 42 | responses.Add(request.CreateResponse(0x7737, BitConverter.GetBytes(swap16((ushort)listOfGuilds.Count)))); 43 | foreach (var guildName in listOfGuilds) 44 | { 45 | responses.Add(request.CreateResponse(0x7738, guildName)); 46 | } 47 | } 48 | return Task.FromResult>(responses); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IClientConnectionService.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace FragmentNetslumServer.Services.Interfaces 4 | { 5 | 6 | /// 7 | /// Defines a service that's responsible for managing the initial listener that accepts connections 8 | /// 9 | /// 10 | /// The implementation of this service should not block at any instance 11 | /// 12 | public interface IClientConnectionService: IBaseService 13 | { 14 | 15 | /// 16 | /// Activates and allows for connections 17 | /// 18 | /// The IP address the service should bind to 19 | /// The port number to listen on 20 | /// 21 | /// can accept a single at a time. Subsequent calls to this method will basically not work 22 | /// 23 | void BeginListening(string ipAddress, ushort port); 24 | 25 | /// 26 | /// Activates and allows for connections 27 | /// 28 | /// The IP address the service should bind to 29 | /// The port number to listen on 30 | /// 31 | /// can accept a single at a time. Subsequent calls to this method will basically not work 32 | /// 33 | void BeginListening(IPAddress ipAddress, ushort port); 34 | 35 | /// 36 | /// Disables and no longer accepts more connections 37 | /// 38 | /// 39 | /// As a programmer note, this is more like disabling a 'login' server rather than shutting down existing connections 40 | /// 41 | void EndListening(); 42 | 43 | /// 44 | /// Restarts in the event that it was shutdown 45 | /// 46 | /// 47 | /// This method will do nothing if the system is still running properly 48 | /// 49 | void RestartService(); 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Helpers/IPAddressHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.NetworkInformation; 3 | using System.Net.Sockets; 4 | 5 | namespace FragmentNetslumServer.Helpers 6 | { 7 | 8 | /// 9 | /// Some IP address related helper functions 10 | /// 11 | public static class IPAddressHelpers 12 | { 13 | 14 | /// 15 | /// Defines, as a global constant, the permanent loopback IP address (aka LOCALHOST) 16 | /// 17 | public const string LOOPBACK_IP_ADDRESS = "127.0.0.1"; 18 | 19 | 20 | /// 21 | /// Selects an IPv4 address to use instead of 127.0.0.1 22 | /// 23 | public static string GetLocalIPAddress() 24 | { 25 | 26 | // Get a list of all network interfaces (usually one per network card, dialup, and VPN connection) 27 | NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); 28 | 29 | foreach (NetworkInterface network in networkInterfaces) 30 | { 31 | // Read the IP configuration for each network 32 | IPInterfaceProperties properties = network.GetIPProperties(); 33 | 34 | // Each network interface may have multiple IP addresses 35 | foreach (IPAddressInformation address in properties.UnicastAddresses) 36 | { 37 | // We're only interested in IPv4 addresses for now 38 | if (address.Address.AddressFamily != AddressFamily.InterNetwork) 39 | continue; 40 | 41 | // Ignore loopback addresses (e.g., 127.0.0.1) 42 | if (IPAddress.IsLoopback(address.Address)) 43 | continue; 44 | 45 | return address.Address.ToString(); 46 | } 47 | } 48 | 49 | return "0.0.0.0"; 50 | 51 | } 52 | 53 | 54 | public static string GetLocalIPAddress2() 55 | { 56 | var addresses = Dns.GetHostAddresses(Dns.GetHostName()); 57 | foreach (IPAddress a in addresses) 58 | { 59 | if (a.AddressFamily == AddressFamily.InterNetwork) 60 | { 61 | return a.ToString(); 62 | } 63 | } 64 | 65 | return "0.0.0.0"; 66 | 67 | } 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/BBS/OPCODE_DATA_BBS_GETMENU.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using static FragmentNetslumServer.Services.Extensions; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.BBS 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_BBS_GETMENU)] 12 | public sealed class OPCODE_DATA_BBS_GETMENU : IOpCodeHandler 13 | { 14 | private readonly IBulletinBoardService bulletinBoardService; 15 | 16 | public OPCODE_DATA_BBS_GETMENU(IBulletinBoardService bulletinBoardService) 17 | { 18 | this.bulletinBoardService = bulletinBoardService ?? throw new ArgumentNullException(nameof(bulletinBoardService)); 19 | } 20 | 21 | public async Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | var responses = new List(); 24 | var u = swap16(BitConverter.ToUInt16(request.Data, 0)); 25 | if (u == 0) 26 | { 27 | var categoryList = await bulletinBoardService.GetCategoriesAsync(); 28 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_BBS_CATEGORYLIST, BitConverter.GetBytes(swap16((ushort)categoryList.Count)))); 29 | foreach (var category in categoryList) 30 | { 31 | var categoryData = await bulletinBoardService.ConvertCategoryToBytesAsync(category); 32 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_BBS_ENTRY_CATEGORY, categoryData)); 33 | } 34 | } 35 | else 36 | { 37 | var categoryID = Convert.ToInt32(u); 38 | var threadsList = await bulletinBoardService.GetThreadsAsync(categoryID); 39 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_BBS_THREADLIST, BitConverter.GetBytes(swap16((ushort)threadsList.Count)))); 40 | foreach (var thread in threadsList) 41 | { 42 | var threadData = await bulletinBoardService.ConvertThreadToBytesAsync(thread); 43 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_BBS_ENTRY_THREAD, threadData)); 44 | } 45 | } 46 | return responses; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/IClientProviderService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Net.Sockets; 3 | using FragmentNetslumServer.Entities; 4 | 5 | namespace FragmentNetslumServer.Services.Interfaces 6 | { 7 | /// 8 | /// Defines a service that's responsible for managing connected client 9 | /// 10 | public interface IClientProviderService: IBaseService 11 | { 12 | 13 | /// 14 | /// Gets a collection of currently connected instances 15 | /// 16 | ReadOnlyCollection Clients { get; } 17 | 18 | /// 19 | /// Gets a collection of currently connected that have declared themselves as Area Servers 20 | /// 21 | ReadOnlyCollection AreaServers { get; } 22 | 23 | 24 | 25 | /// 26 | /// Adds a new client to the 27 | /// 28 | /// The newly connected 29 | /// An identifier for the client 30 | void AddClient(TcpClient client, uint clientId); 31 | 32 | /// 33 | /// Adds a new client to the 34 | /// 35 | /// The newly created 36 | void AddClient(GameClientAsync client); 37 | 38 | 39 | /// 40 | /// Removes an existing client from 41 | /// 42 | /// The identifier for the client 43 | void RemoveClient(uint clientId); 44 | 45 | /// 46 | /// Removes an existing client from 47 | /// 48 | /// to remove 49 | void RemoveClient(GameClientAsync client); 50 | 51 | /// 52 | /// Attempts to retrieve a based on its index 53 | /// 54 | /// The expected client index 55 | /// The 56 | /// A boolean value to indicate success or failure 57 | bool TryGetClient(uint index, out GameClientAsync client); 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Lobby/OPCODE_DATA_LOBBY_ENTERROOM.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using Serilog; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.Threading.Tasks; 8 | using static FragmentNetslumServer.Services.Extensions; 9 | 10 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Lobby 11 | { 12 | 13 | [OpCodeData(OpCodes.OPCODE_DATA_LOBBY_ENTERROOM), Description("Informs a Lobby that a new Client has joined")] 14 | public sealed class OPCODE_DATA_LOBBY_ENTERROOM : IOpCodeHandler 15 | { 16 | private readonly ILobbyChatService lobbyChatService; 17 | private readonly ILogger logger; 18 | 19 | public OPCODE_DATA_LOBBY_ENTERROOM(ILobbyChatService lobbyChatService, ILogger logger) 20 | { 21 | this.lobbyChatService = lobbyChatService ?? throw new ArgumentNullException(nameof(lobbyChatService)); 22 | this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); 23 | } 24 | 25 | public Task> HandleIncomingRequestAsync(RequestContent request) 26 | { 27 | List responseList = new List(); 28 | LobbyChatRoom room; 29 | var currentLobbyIndex = (short)swap16(BitConverter.ToUInt16(request.Data, 0)); 30 | var currentLobbyType = swap16(BitConverter.ToUInt16(request.Data, 2)); 31 | logger.Verbose("Lobby Room ID: {@room_index}", currentLobbyIndex); 32 | logger.Verbose("Lobby Type ID: {@lobbyType}", currentLobbyType); 33 | 34 | if (currentLobbyType == OpCodes.LOBBY_TYPE_GUILD) //Guild Room 35 | { 36 | //TODO add Guild Specific Code 37 | room = lobbyChatService.GetOrAddLobby((ushort)currentLobbyIndex, "Guild Room", OpCodes.LOBBY_TYPE_GUILD, out var _); 38 | } 39 | else 40 | { 41 | lobbyChatService.TryGetLobby((ushort)currentLobbyIndex, out room); 42 | } 43 | 44 | responseList.Add(request.CreateResponse(OpCodes.OPCODE_DATA_LOBBY_ENTERROOM_OK, BitConverter.GetBytes(swap16((ushort)room.Clients.Count)))); 45 | responseList.AddRange(room.ClientJoinedLobbyPacketHandler(request.Client,request)); 46 | logger.Information("Client #{0} has joined Lobby {1}. There are now {2} client(s) in the room", request.Client.ClientIndex, room.Name, room.Clients.Count ); 47 | return Task.FromResult>(responseList); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Ranking/OPCODE_RANKING_VIEW_ALL.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using FragmentNetslumServer.Entities.Attributes; 5 | using FragmentNetslumServer.Services; 6 | using FragmentNetslumServer.Services.Interfaces; 7 | 8 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Ranking 9 | { 10 | [OpCodeData(OpCodes.OPCODE_RANKING_VIEW_ALL)] 11 | public sealed class OPCODE_RANKING_VIEW_ALL : IOpCodeHandler 12 | { 13 | private readonly IRankingManagementService _rankingManagementService; 14 | 15 | public OPCODE_RANKING_VIEW_ALL(IRankingManagementService rankingManagementService) 16 | { 17 | _rankingManagementService = rankingManagementService; 18 | } 19 | 20 | public Task> HandleIncomingRequestAsync(RequestContent request) 21 | { 22 | List responseContents = new List(); 23 | var rankingArgs = (BitConverter.ToUInt16(request.Data, 0).Swap()); 24 | if (rankingArgs == 0) // get the first ranking page 25 | { 26 | var rankCategoryList = _rankingManagementService.GetRankingCategory(); 27 | 28 | responseContents.Add(request.CreateResponse(0x7833, 29 | BitConverter.GetBytes(((ushort)rankCategoryList.Count).Swap()))); 30 | 31 | foreach (var category in rankCategoryList) 32 | { 33 | responseContents.Add(request.CreateResponse(0x7835, category)); 34 | } 35 | } 36 | else if (rankingArgs >= 8) // get class List 37 | { 38 | request.Client._rankingCategoryID = rankingArgs; 39 | var rankClassList = Extensions.GetClassList(); 40 | responseContents.Add(request.CreateResponse(0x7833, BitConverter.GetBytes(((ushort)rankClassList.Count).Swap()))); 41 | foreach (var category in rankClassList) 42 | { 43 | responseContents.Add(request.CreateResponse(0x7835, category)); 44 | } 45 | } 46 | else 47 | { 48 | var playerRankingList = _rankingManagementService.GetPlayerRanking(request.Client._rankingCategoryID, rankingArgs); 49 | responseContents.Add(request.CreateResponse(0x7836, BitConverter.GetBytes(((uint)playerRankingList.Count).Swap()))); 50 | foreach (var player in playerRankingList) 51 | { 52 | responseContents.Add(request.CreateResponse(0x7837, player)); 53 | } 54 | } 55 | 56 | return Task.FromResult>(responseContents); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /FragmentNetslumServer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30406.217 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FragmentNetslumServer", "FragmentNetslumServer\FragmentNetslumServer.csproj", "{E24F2253-4792-4DB6-AA71-7262CA891A3C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FragmentNetslumServerLauncher", "FragmentNetslumServerLauncher\FragmentNetslumServerLauncher.csproj", "{F1360378-9ED1-46D6-AB60-1CF4F1B79F96}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FragmentNetslumServerWebApi", "FragmentNetslumServerWebApi\FragmentNetslumServerWebApi.csproj", "{A6BB141E-02F4-46EB-82E4-B7A02D86F1E8}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FragmentNetslumServerPubSub", "FragmentNetslumServerPubSub\FragmentNetslumServerPubSub.csproj", "{B19DBDC7-2568-4E63-A140-F6E0AB9BB5E5}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {E24F2253-4792-4DB6-AA71-7262CA891A3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {E24F2253-4792-4DB6-AA71-7262CA891A3C}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {E24F2253-4792-4DB6-AA71-7262CA891A3C}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {E24F2253-4792-4DB6-AA71-7262CA891A3C}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {F1360378-9ED1-46D6-AB60-1CF4F1B79F96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {F1360378-9ED1-46D6-AB60-1CF4F1B79F96}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {F1360378-9ED1-46D6-AB60-1CF4F1B79F96}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {F1360378-9ED1-46D6-AB60-1CF4F1B79F96}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {A6BB141E-02F4-46EB-82E4-B7A02D86F1E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {A6BB141E-02F4-46EB-82E4-B7A02D86F1E8}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {A6BB141E-02F4-46EB-82E4-B7A02D86F1E8}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {A6BB141E-02F4-46EB-82E4-B7A02D86F1E8}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {B19DBDC7-2568-4E63-A140-F6E0AB9BB5E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {B19DBDC7-2568-4E63-A140-F6E0AB9BB5E5}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {B19DBDC7-2568-4E63-A140-F6E0AB9BB5E5}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {B19DBDC7-2568-4E63-A140-F6E0AB9BB5E5}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {2CCF6F06-C7E8-47F1-A7C5-39C6ED7CC7D7} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/News/OPCODE_DATA_NEWS_GETMENU.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using FragmentNetslumServer.Entities.Attributes; 7 | using FragmentNetslumServer.Models; 8 | using FragmentNetslumServer.Services; 9 | using FragmentNetslumServer.Services.Interfaces; 10 | 11 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.News 12 | { 13 | [OpCodeData(OpCodes.OPCODE_DATA_NEWS_GETMENU) , Description("Get List of Articles")] 14 | public sealed class OPCODE_DATA_NEWS_GETMENU : IOpCodeHandler 15 | { 16 | private readonly INewsService _newsService; 17 | private readonly Encoding _encoding; 18 | 19 | public OPCODE_DATA_NEWS_GETMENU(INewsService newsService) 20 | { 21 | _newsService = newsService; 22 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 23 | _encoding = Encoding.GetEncoding("Shift-JIS"); 24 | } 25 | 26 | public async Task> HandleIncomingRequestAsync(RequestContent request) 27 | { 28 | var u = BitConverter.ToUInt16(request.Data, 0).Swap(); // Get CategoryID 29 | 30 | // we are skipping category listing and we will list only the articles , but either way here is the code for it 31 | 32 | // Ignore categories only send the article list 33 | /*if (u == 0) 34 | { 35 | ushort count = 1; 36 | await SendDataPacket(OpCodes.OPCODE_DATA_NEWS_CATEGORYLIST, BitConverter.GetBytes(swap16(count))); 37 | 38 | ushort catID = 1; 39 | string catName = "Testing Category"; 40 | using MemoryStream memoryStream = new MemoryStream(); 41 | await memoryStream.WriteAsync(BitConverter.GetBytes(swap16(catID))); 42 | await memoryStream.WriteAsync(encoding.GetBytes(catName + char.MinValue)); 43 | await SendDataPacket(OpCodes.OPCODE_DATA_NEWS_ENTRY_CATEGORY, memoryStream.ToArray()); 44 | } else*/ 45 | List listOfResponse = new List(); 46 | 47 | // send articles 48 | ushort count = (ushort)(await _newsService.GetNewsArticles()).Count; 49 | listOfResponse.Add(request.CreateResponse(OpCodes.OPCODE_DATA_NEWS_ARTICLELIST, 50 | BitConverter.GetBytes((count.Swap())))); 51 | 52 | foreach (NewsSectionModel article in 53 | (await _newsService.GetNewsArticles( 54 | _encoding.GetString(request.Client 55 | .save_id)))) // get the articles data and set the isNew flag based on the saveID 56 | { 57 | listOfResponse.Add(request.CreateResponse(OpCodes.OPCODE_DATA_NEWS_ENTRY_ARTICLE, 58 | article.ArticleByteArray)); 59 | } 60 | 61 | return listOfResponse; 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Models/Mapping/CharacterRepositoryModel.hbm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/RequestContent.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System; 3 | using static FragmentNetslumServer.Services.Extensions; 4 | 5 | namespace FragmentNetslumServer.Entities 6 | { 7 | 8 | /// 9 | /// Defines a particular request that was sent via a connected client 10 | /// 11 | public sealed class RequestContent 12 | { 13 | 14 | /// 15 | /// Gets the that has submitted this request 16 | /// 17 | public GameClientAsync Client { get; private set; } 18 | 19 | /// 20 | /// Gets the OpCode that was submitted by the 21 | /// 22 | public ushort OpCode { get; private set; } 23 | 24 | /// 25 | /// Gets the optional Data OpCode that was submitted by the 26 | /// 27 | /// 28 | /// If does not equal (or 0x30) then this will be NULL 29 | /// 30 | public ushort? DataOpCode { get; private set; } 31 | 32 | /// 33 | /// Gets the data payload that was submitted by the 34 | /// 35 | public byte[] Data { get; private set; } 36 | 37 | 38 | 39 | /// 40 | /// Creates a new instance for the given client and packet 41 | /// 42 | /// The that has received a packet of information 43 | /// The of data that was received 44 | public RequestContent( 45 | GameClientAsync gameClient, 46 | PacketAsync packet) 47 | { 48 | this.Client = gameClient; 49 | this.OpCode = packet.Code; 50 | this.Data = packet.Data; 51 | 52 | if (this.OpCode == OpCodes.OPCODE_DATA) 53 | { 54 | 55 | // For the DATA opcode, we have some special handling 56 | // that needs to occur now. This additional logic is 57 | // responsible for the "data opcode" and also properly 58 | // decoding the data payload 59 | var data = packet.Data; 60 | if (Client != null) // Client can be NULL if we're just asking 'can we handle this' 61 | { 62 | Client.SetClientSequenceNumber(swap16(BitConverter.ToUInt16(data, 2))); 63 | } 64 | var arglen = (ushort)(swap16(BitConverter.ToUInt16(data, 6)) - 2); 65 | var code = swap16(BitConverter.ToUInt16(data, 8)); 66 | var m = new MemoryStream(); 67 | m.Write(data, 10, arglen); 68 | 69 | this.DataOpCode = code; 70 | this.Data = m.ToArray(); 71 | } 72 | 73 | } 74 | 75 | /// 76 | /// A shortcut method to create a response 77 | /// 78 | /// The OpCode to respond with 79 | /// The data to transmit 80 | /// An optional checksum of the data 81 | /// 82 | public ResponseContent CreateResponse( 83 | ushort responseOpCode, 84 | byte[] responseData, 85 | uint? checksum = null) 86 | { 87 | return new ResponseContent(this, responseOpCode, responseData, checksum); 88 | } 89 | 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_NORESPONSE.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FragmentNetslumServer.Entities.Attributes; 4 | using System.ComponentModel; 5 | using System.IO; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using FragmentNetslumServer.Services; 9 | using FragmentNetslumServer.Services.Interfaces; 10 | using Serilog; 11 | 12 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 13 | { 14 | [OpCodeData(OpCodes.OPCODE_DATA_PING), 15 | OpCodeData(OpCodes.OPCODE_DATA_LOBBY_FAVORITES_AS_INQUIRY), 16 | OpCodeData(OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS3), 17 | OpCodeData(OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS4), 18 | OpCodeData(OpCodes.OPCODE_DATA_AS_PUBLISH_DETAILS6), 19 | Description("Provides no response to DATA OpCodes")] 20 | public sealed class OPCODE_DATA_NORESPONSE : NoResponseOpCodeHandler 21 | { 22 | private readonly ILogger logger; 23 | private readonly IClientProviderService clientProviderService; 24 | 25 | public OPCODE_DATA_NORESPONSE(ILogger logger, IClientProviderService clientProviderService) 26 | { 27 | this.logger = logger; 28 | this.clientProviderService = clientProviderService; 29 | } 30 | 31 | public override async Task> HandleIncomingRequestAsync(RequestContent request) 32 | { 33 | var responses = new List(); 34 | if (request.DataOpCode == OpCodes.OPCODE_DATA_LOBBY_FAVORITES_AS_INQUIRY) 35 | { 36 | logger.LogData(request.Data,request.OpCode,request.Client.ClientIndex,"Get Bookmark",0,0); 37 | var encoding = Encoding.GetEncoding("Shift-JIS"); 38 | var areaServers = clientProviderService.AreaServers; 39 | responses.Add(request.CreateResponse(0x7859, BitConverter.GetBytes(((ushort)areaServers.Count).Swap()))); 40 | 41 | // Now we need to send all the area servers to the client 42 | foreach (var client in areaServers) 43 | { 44 | var m = new MemoryStream(); 45 | m.WriteByte(0); 46 | if (client.ipEndPoint.Address == request.Client.ipEndPoint.Address) 47 | await m.WriteAsync(client.ipdata, 0, 6); 48 | else 49 | await m.WriteAsync(client.externalIPAddress, 0, 6); 50 | 51 | var buff = BitConverter.GetBytes((client.as_usernum.Swap())); 52 | int pos = 0; 53 | while (client.publish_data_1[pos++] != 0) ; 54 | pos += 4; 55 | client.publish_data_1[pos++] = buff[0]; 56 | client.publish_data_1[pos++] = buff[1]; 57 | await m.WriteAsync(client.publish_data_1, 0, client.publish_data_1.Length); 58 | while (m.Length < 45) m.WriteByte(0); 59 | 60 | var usr = encoding.GetString(BitConverter.GetBytes((client.as_usernum.Swap()))); 61 | var pup1 = encoding.GetString(client.publish_data_1); 62 | var pup2 = encoding.GetString(client.publish_data_2); 63 | logger.Debug($"AREA SERVER: {pup1}; {pup2}; {usr}", pup1, pup2, usr); 64 | 65 | responses.Add(request.CreateResponse(0x786A, m.ToArray())); 66 | } 67 | 68 | return responses; 69 | } 70 | 71 | 72 | else 73 | { 74 | return await base.HandleIncomingRequestAsync(request); 75 | } 76 | 77 | 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/Interfaces/ILobbyChatService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Threading.Tasks; 3 | using FragmentNetslumServer.Entities; 4 | 5 | namespace FragmentNetslumServer.Services.Interfaces 6 | { 7 | 8 | /// 9 | /// Defines how the lobby service system should operate 10 | /// 11 | public interface ILobbyChatService: IBaseService 12 | { 13 | 14 | /// 15 | /// Gets a collection of currently created Lobbies 16 | /// 17 | ReadOnlyDictionary Lobbies { get; } 18 | 19 | /// 20 | /// Gets the main lobby room 21 | /// 22 | LobbyChatRoom Main { get; } 23 | 24 | /// 25 | /// Returns an instance of 26 | /// 27 | /// The unique Lobby ID 28 | /// The name of the lobby to create 29 | /// The type of lobby to create 30 | /// Indicates if the supplied already existed 31 | /// 32 | /// For more information on the correct TYPE to pass in, take a look in 33 | LobbyChatRoom GetOrAddLobby(ushort lobbyId, string lobbyName, ushort lobbyType, out bool isCreated); 34 | 35 | /// 36 | /// Attempts to retrieve a 37 | /// 38 | /// The unique Lobby ID 39 | /// The found, if applicable 40 | /// 41 | bool TryGetLobby(ushort lobbyId, out LobbyChatRoom lobbyChatRoom); 42 | 43 | /// 44 | /// Announces that a client has left a particular 45 | /// 46 | /// 47 | /// The identifier of the client 48 | /// A Task that intends to complete the departure announcement 49 | Task AnnounceRoomDeparture(LobbyChatRoom lobbyChatRoom, uint clientIndex); 50 | 51 | /// 52 | /// Announces that a client has left a particular 53 | /// 54 | /// The lobby identifier 55 | /// The identifier of the client 56 | /// A Task that intends to complete the departure announcement 57 | Task AnnounceRoomDeparture(ushort lobbyId, uint clientIndex); 58 | 59 | /// 60 | /// Attempts to locate the lobby where the client is currently at 61 | /// 62 | /// The index of the client 63 | /// The discovered 64 | /// True or false depending on whether or not the lobby was found 65 | bool TryFindLobby(uint clientIndex, out LobbyChatRoom lobbyChatRoom); 66 | 67 | /// 68 | /// Attempts to locate the lobby where the client is currently at 69 | /// 70 | /// The game client reference 71 | /// The discovered 72 | /// True or false depending on whether or not the lobby was found 73 | bool TryFindLobby(GameClientAsync gameClientAsync, out LobbyChatRoom lobbyChatRoom); 74 | 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/GameClientService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Net.Sockets; 6 | using FragmentNetslumServer.Entities; 7 | using FragmentNetslumServer.Enumerations; 8 | using FragmentNetslumServer.Services.Interfaces; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using Serilog; 11 | 12 | namespace FragmentNetslumServer.Services 13 | { 14 | public sealed class GameClientService : IClientProviderService 15 | { 16 | 17 | private readonly List clients; 18 | private readonly ILogger logger; 19 | private readonly ILobbyChatService lobbyChatService; 20 | private readonly IServiceProvider provider; 21 | 22 | public ReadOnlyCollection Clients => clients.AsReadOnly(); 23 | 24 | public ReadOnlyCollection AreaServers => clients.Where(c => c.isAreaServer).ToList().AsReadOnly(); 25 | 26 | public string ServiceName => "Game Client Service"; 27 | 28 | public ServiceStatusEnum ServiceStatus { get; private set; } 29 | 30 | 31 | 32 | public GameClientService(ILogger logger,ILobbyChatService lobbyChatService ,IServiceProvider provider) 33 | { 34 | this.logger = logger; 35 | this.lobbyChatService = lobbyChatService; 36 | this.provider = provider; 37 | this.clients = new List(); 38 | this.ServiceStatus = ServiceStatusEnum.Active; 39 | } 40 | 41 | 42 | 43 | public void AddClient(TcpClient client, uint clientId) 44 | { 45 | var gameClient = provider.GetRequiredService(); 46 | gameClient.InitializeClient(clientId, client); 47 | this.AddClient(gameClient); 48 | } 49 | 50 | public void AddClient(GameClientAsync client) 51 | { 52 | this.logger.Information($"Client {client.ClientIndex} has connected"); 53 | client.OnGameClientDisconnected += Client_OnGameClientDisconnected; 54 | this.clients.Add(client); 55 | this.logger.Information($"There are {clients.Count:N0} connected clients"); 56 | 57 | } 58 | 59 | public void RemoveClient(uint index) => this.RemoveClient(clients.Find(c => c.ClientIndex == (int)index)); 60 | 61 | public void RemoveClient(GameClientAsync client) 62 | { 63 | this.logger.Information($"Client {client.ClientIndex} has disconnected"); 64 | this.clients.Remove(client); 65 | this.logger.Information($"There are {clients.Count:N0} connected clients"); 66 | } 67 | 68 | public bool TryGetClient(uint index, out GameClientAsync client) 69 | { 70 | client = null; 71 | foreach (var c in clients) 72 | { 73 | if (c.ClientIndex == index) 74 | { 75 | client = c; 76 | return true; 77 | } 78 | } 79 | return false; 80 | } 81 | 82 | private void Client_OnGameClientDisconnected(object sender, EventArgs e) 83 | { 84 | if (!(sender is GameClientAsync client)) return; 85 | RemoveClient(client); 86 | if (client.PlayerID != 0) 87 | { 88 | DBAccess.getInstance().setPlayerAsOffline(client.PlayerID); 89 | } 90 | if (!client.IsAreaServer && lobbyChatService.TryFindLobby(client, out var lobby)) 91 | { 92 | lobbyChatService.AnnounceRoomDeparture(lobby, (uint)client.ClientIndex); 93 | } 94 | client.OnGameClientDisconnected -= Client_OnGameClientDisconnected; 95 | } 96 | 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /FragmentNetslumServer/FragmentNetslumServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | Library 5 | 6 | 7 | false 8 | FragmentNetslumServer 9 | FragmentNetslumServer 10 | 11 | 12 | TRACE;USE_HYBRID_APPROACH 13 | 14 | 15 | TRACE;USE_HYBRID_APPROACH 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 71 | 72 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Services/LobbyChatService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Collections.ObjectModel; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using FragmentNetslumServer.Entities; 6 | using FragmentNetslumServer.Enumerations; 7 | using FragmentNetslumServer.Services.Interfaces; 8 | using Serilog; 9 | 10 | namespace FragmentNetslumServer.Services 11 | { 12 | public sealed class LobbyChatService : ILobbyChatService 13 | { 14 | 15 | private readonly ConcurrentDictionary lobbies; 16 | private readonly ILogger logger; 17 | private LobbyChatRoom mainLobby; 18 | 19 | public ReadOnlyDictionary Lobbies => new ReadOnlyDictionary(lobbies); 20 | 21 | public LobbyChatRoom Main => mainLobby; 22 | 23 | public string ServiceName => "Lobby Service"; 24 | 25 | public ServiceStatusEnum ServiceStatus { get; private set; } = ServiceStatusEnum.Inactive; 26 | 27 | public LobbyChatService(ILogger logger) 28 | { 29 | this.logger = logger; 30 | this.lobbies = new ConcurrentDictionary(); 31 | this.ServiceStatus = ServiceStatusEnum.Active; 32 | this.mainLobby = GetOrAddLobby(1, "Main Lobby", OpCodes.LOBBY_TYPE_MAIN, out var _); 33 | } 34 | 35 | 36 | public LobbyChatRoom GetOrAddLobby(ushort lobbyId, string lobbyName, ushort lobbyType, out bool isCreated) 37 | { 38 | var localCreated = false; 39 | this.logger.Debug("Looking for a Lobby of ID {@lobbyId}", lobbyId); 40 | var lobby = lobbies.GetOrAdd(lobbyId, _ => 41 | { 42 | localCreated = true; 43 | this.logger.Debug("Lobby {@lobbyId} does not exist. Creating a new Lobby named '{@lobbyName}'", lobbyId, lobbyName); 44 | return new LobbyChatRoom(lobbyName, lobbyId, lobbyType); 45 | }); 46 | isCreated = localCreated; 47 | return lobby; 48 | } 49 | 50 | public bool TryGetLobby(ushort lobbyId, out LobbyChatRoom lobbyChatRoom) 51 | { 52 | this.logger.Debug("Looking for a Lobby of ID {@lobbyId}", lobbyId); 53 | lobbyChatRoom = null; 54 | if (lobbies.ContainsKey(lobbyId)) 55 | { 56 | lobbyChatRoom = lobbies[lobbyId]; 57 | this.logger.Debug("Found Lobby ID {@lobbyId}", lobbyId); 58 | return true; 59 | } 60 | this.logger.Debug("Could not find {@lobbyId}", lobbyId); 61 | return false; 62 | } 63 | 64 | public async Task AnnounceRoomDeparture(LobbyChatRoom lobbyChatRoom, uint clientIndex) 65 | { 66 | logger.Debug("Client #{@clientIndex} is leaving their lobby", clientIndex); 67 | await lobbyChatRoom.ClientLeavingRoomAsync((int)clientIndex); 68 | logger.Debug($"Lobby '{lobbyChatRoom.Name}' now has {lobbyChatRoom.Clients.Count:N0} Users"); 69 | await Task.Yield(); 70 | } 71 | 72 | public async Task AnnounceRoomDeparture(ushort lobbyId, uint clientIndex) 73 | { 74 | if (TryGetLobby(lobbyId, out var lobby)) 75 | { 76 | await AnnounceRoomDeparture(lobby, clientIndex); 77 | } 78 | } 79 | 80 | public bool TryFindLobby(uint clientIndex, out LobbyChatRoom lobbyChatRoom) 81 | { 82 | lobbyChatRoom = null; 83 | foreach(var lobby in Lobbies) 84 | { 85 | var lobbyId = lobby.Key; 86 | var lcr = lobby.Value; 87 | if (lcr.Clients.Any(c => c.ClientIndex == clientIndex)) 88 | { 89 | lobbyChatRoom = lcr; 90 | return true; 91 | } 92 | } 93 | return false; 94 | } 95 | 96 | public bool TryFindLobby(GameClientAsync gameClientAsync, out LobbyChatRoom lobbyChatRoom) 97 | { 98 | return TryFindLobby((uint)gameClientAsync.ClientIndex, out lobbyChatRoom); 99 | } 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/OPCODE_DATA_REGISTER_CHAR.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services; 3 | using FragmentNetslumServer.Services.Interfaces; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading.Tasks; 7 | using static FragmentNetslumServer.Services.Extensions; 8 | 9 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data 10 | { 11 | [OpCodeData(OpCodes.OPCODE_DATA_REGISTER_CHAR)] 12 | public sealed class OPCODE_DATA_REGISTER_CHAR : IOpCodeHandler 13 | { 14 | private readonly IGuildManagementService guildManagementService; 15 | 16 | public OPCODE_DATA_REGISTER_CHAR(IGuildManagementService guildManagementService) 17 | { 18 | this.guildManagementService = guildManagementService; 19 | } 20 | 21 | public Task> HandleIncomingRequestAsync(RequestContent request) 22 | { 23 | request.Client._characterPlayerID = ExtractCharacterData(request.Client, request.Data); 24 | byte[] guildStatus = guildManagementService.GetPlayerGuild(request.Client._characterPlayerID); 25 | if (guildStatus[0] == 0x01) 26 | { 27 | request.Client.isGuildMaster = true; 28 | } 29 | request.Client._guildID = swap16(BitConverter.ToUInt16(guildStatus, 1)); 30 | // The first byte is membership status: 0=none 1= master 2= member 31 | return Task.FromResult>(new[] { request.CreateResponse(OpCodes.OPCODE_DATA_REGISTER_CHAROK, guildStatus) }); 32 | } 33 | 34 | uint ExtractCharacterData(GameClientAsync client, byte[] data) 35 | { 36 | client.save_slot = data[0]; 37 | client.char_id = ReadByteString(data, 1); 38 | int pos = 1 + client.char_id.Length; 39 | client.char_name = ReadByteString(data, pos); 40 | pos += client.char_name.Length; 41 | client.char_class = data[pos++]; 42 | client.char_level = swap16(BitConverter.ToUInt16(data, pos)); 43 | pos += 2; 44 | client.greeting = ReadByteString(data, pos); 45 | pos += client.greeting.Length; 46 | client.char_model = swap32(BitConverter.ToUInt32(data, pos)); 47 | pos += 5; 48 | client.char_HP = swap16(BitConverter.ToUInt16(data, pos)); 49 | pos += 2; 50 | client.char_SP = swap16(BitConverter.ToUInt16(data, pos)); 51 | pos += 2; 52 | client.char_GP = swap32(BitConverter.ToUInt32(data, pos)); 53 | pos += 4; 54 | client.online_god_counter = swap16(BitConverter.ToUInt16(data, pos)); 55 | pos += 2; 56 | client.offline_godcounter = swap16(BitConverter.ToUInt16(data, pos)); 57 | pos += 2; 58 | client.goldCoinCount = swap16(BitConverter.ToUInt16(data, pos)); 59 | pos += 2; 60 | client.silverCoinCount = swap16(BitConverter.ToUInt16(data, pos)); 61 | pos += 2; 62 | client.bronzeCoinCount = swap16(BitConverter.ToUInt16(data, pos)); 63 | 64 | client.classLetter = GetCharacterModelClass(client.char_model); 65 | client.modelNumber = GetCharacterModelNumber(client.char_model); 66 | client.modelType = GetCharacterModelType(client.char_model); 67 | client.colorCode = GetCharacterModelColorCode(client.char_model); 68 | 69 | client.charModelFile = "xf" + client.classLetter + client.modelNumber + client.modelType + "_" + client.colorCode; 70 | return DBAccess.getInstance().PlayerLogin(client); 71 | } 72 | 73 | static char GetCharacterModelClass(uint modelNumber) 74 | { 75 | char[] classLetters = { 't', 'b', 'h', 'a', 'l', 'w' }; 76 | int index = (int)(modelNumber & 0x0F); 77 | return classLetters[index]; 78 | } 79 | 80 | static int GetCharacterModelNumber(uint modelNumber) 81 | { 82 | return (int)(modelNumber >> 4 & 0x0F) + 1; 83 | } 84 | 85 | static char GetCharacterModelType(uint modelNumber) 86 | { 87 | char[] typeLetters = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' }; 88 | int index = (int)(modelNumber >> 12) & 0x0F; 89 | return typeLetters[index]; 90 | } 91 | 92 | static string GetCharacterModelColorCode(uint modelNumber) 93 | { 94 | string[] colorCodes = { "rd", "bl", "yl", "gr", "br", "pp" }; 95 | int index = (int)(modelNumber >> 8) & 0x0F; 96 | return colorCodes[index]; 97 | } 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /FragmentNetslumServer/Entities/OpCodeHandlers/Data/Lobby/OPCODE_DATA_LOBBY_GETSERVERS_GETLIST.cs: -------------------------------------------------------------------------------- 1 | using FragmentNetslumServer.Entities.Attributes; 2 | using FragmentNetslumServer.Services.Interfaces; 3 | using Serilog; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using static FragmentNetslumServer.Services.Extensions; 10 | 11 | namespace FragmentNetslumServer.Entities.OpCodeHandlers.Data.Lobby 12 | { 13 | 14 | [OpCodeData(OpCodes.OPCODE_DATA_LOBBY_GETSERVERS_GETLIST)] 15 | public sealed class OPCODE_DATA_LOBBY_GETSERVERS_GETLIST : IOpCodeHandler 16 | { 17 | private readonly ILogger logger; 18 | private readonly IClientProviderService clientProviderService; 19 | 20 | public OPCODE_DATA_LOBBY_GETSERVERS_GETLIST(ILogger logger, IClientProviderService clientProviderService) 21 | { 22 | this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); 23 | this.clientProviderService = clientProviderService ?? throw new ArgumentNullException(nameof(clientProviderService)); 24 | } 25 | 26 | public async Task> HandleIncomingRequestAsync(RequestContent request) 27 | { 28 | // Zero indicates "gimme the list of categories" 29 | var encoding = Encoding.GetEncoding("Shift-JIS"); 30 | var responses = new List(); 31 | if (request.Data[1] == 0) 32 | { 33 | 34 | logger.Information("Client #{@clientIndex} has requested the list of available categories for Area Server Selection", new { clientIndex = request.Client.ClientIndex }); 35 | 36 | // Tell the game there's ONE category 37 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_LOBBY_GETSERVERS_CATEGORYLIST, new byte[] { 0x00, 0x01 })); 38 | 39 | // This is the category. This byte array translates to, basically, MAIN: 40 | // "\0\u0001MAIN\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ne" 41 | // Uses \u0001MAIN with the rest as padding, more than likely 42 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_LOBBY_GETSERVERS_ENTRY_CATEGORY, 43 | new byte[] 44 | { 45 | 0x00, 0x01, 0x4D, 0x41, 0x49, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x6E, 0x65 48 | })); 49 | } 50 | else 51 | { 52 | logger.Information("Client #{@clientIndex} has requested the list of area servers for the MAIN category", new { clientIndex = request.Client.ClientIndex }); 53 | 54 | // We don't care about categories any longer. We're here for the list of servers 55 | var areaServers = clientProviderService.AreaServers; 56 | 57 | // Tell the client how many area servers we got 58 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_LOBBY_GETSERVERS_SERVERLIST, BitConverter.GetBytes(swap16((ushort)areaServers.Count)))); 59 | 60 | // Now we need to send all the area servers to the client 61 | foreach (var client in areaServers) 62 | { 63 | var m = new MemoryStream(); 64 | m.WriteByte(0); 65 | if (client.ipEndPoint.Address == request.Client.ipEndPoint.Address) 66 | await m.WriteAsync(client.ipdata, 0, 6); 67 | else 68 | await m.WriteAsync(client.externalIPAddress, 0, 6); 69 | 70 | var buff = BitConverter.GetBytes(swap16(client.as_usernum)); 71 | int pos = 0; 72 | while (client.publish_data_1[pos++] != 0) ; 73 | pos += 4; 74 | client.publish_data_1[pos++] = buff[0]; 75 | client.publish_data_1[pos++] = buff[1]; 76 | await m.WriteAsync(client.publish_data_1, 0, client.publish_data_1.Length); 77 | while (m.Length < 45) m.WriteByte(0); 78 | 79 | var usr = encoding.GetString(BitConverter.GetBytes(swap16(client.as_usernum))); 80 | var pup1 = encoding.GetString(client.publish_data_1); 81 | var pup2 = encoding.GetString(client.publish_data_2); 82 | logger.Debug($"AREA SERVER: {pup1}; {pup2}; {usr}", pup1, pup2, usr); 83 | 84 | responses.Add(request.CreateResponse(OpCodes.OPCODE_DATA_LOBBY_GETSERVERS_ENTRY_SERVER, m.ToArray())); 85 | } 86 | 87 | // Shorten the TTL / ping timer so we can detect more 88 | // quickly when a player disconnects and hops over to an area server. 89 | // pingTimer.Interval = EnhancedPingTimeout.TotalMilliseconds; 90 | 91 | } 92 | return responses; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /FragmentNetslumServerWebApi/Models/PlayerModel.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using FragmentNetslumServer.Entities; 3 | using FragmentNetslumServer.Models; 4 | 5 | namespace FragmentNetslumServerWebApi.Models 6 | { 7 | public class PlayerModel 8 | { 9 | public int save_slot; 10 | public string save_id; 11 | public string char_id; 12 | public string char_name; 13 | public string char_class; 14 | public int char_level; 15 | public string greeting; 16 | public int char_model; 17 | public string charModelFile; 18 | public int char_HP; 19 | public int char_SP; 20 | public int char_GP; 21 | public int online_god_counter; 22 | public int offline_godCounter; 23 | 24 | public static PlayerModel ConvertData(GameClientAsync client) 25 | { 26 | PlayerModel model = new PlayerModel(); 27 | 28 | /* 29 | * 30 | *Console.WriteLine("Character Date \n save_slot "+ save_slot + "\n char_id " +Encoding.ASCII.GetString(save_id) + " \n char_name " + Encoding.ASCII.GetString(char_id) + 31 | "\n char_class " + char_class + "\n char_level " + char_level + "\n greeting "+ Encoding.ASCII.GetString(greeting) +"\n charmodel " +char_model + "\n char_hp " + char_HP+ 32 | "\n char_sp " + char_SP + "\n char_gp " + char_GP + "\n onlien god counter "+ online_god_counter + "\n offline god counter "+ offline_godcounter +"\n\n\n\n full byte araray " + BitConverter.ToString(data)); 33 | * 34 | */ 35 | 36 | if (null == client.save_id || null == client.char_id || 37 | null == client.char_name || null == client.greeting) 38 | return null; 39 | 40 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 41 | 42 | model.save_slot = client.save_slot; 43 | model.save_id = Encoding.GetEncoding("Shift-JIS").GetString(client.save_id,0,client.save_id.Length-1); 44 | model.char_id = Encoding.GetEncoding("Shift-JIS").GetString(client.char_id,0,client.char_id.Length-1); 45 | model.char_name = Encoding.GetEncoding("Shift-JIS").GetString(client.char_name,0,client.char_name.Length-1); 46 | 47 | PlayerClass playerClass = (PlayerClass) client.char_class; 48 | model.char_class = playerClass.ToString(); 49 | model.char_level = client.char_level; 50 | 51 | model.greeting = Encoding.GetEncoding("Shift-JIS").GetString(client.greeting,0,client.greeting.Length-1); 52 | model.char_model = (int) client.char_model; 53 | model.char_HP = client.char_HP; 54 | model.char_SP = client.char_SP; 55 | model.char_GP = (int) client.char_GP; 56 | model.online_god_counter = client.online_god_counter; 57 | model.offline_godCounter = client.offline_godcounter; 58 | model.charModelFile = client.charModelFile; 59 | 60 | return model; 61 | } 62 | 63 | public int SaveSlot 64 | { 65 | get => save_slot; 66 | set => save_slot = value; 67 | } 68 | 69 | public string SaveId 70 | { 71 | get => save_id; 72 | set => save_id = value; 73 | } 74 | 75 | public string CharId 76 | { 77 | get => char_id; 78 | set => char_id = value; 79 | } 80 | 81 | public string CharName 82 | { 83 | get => char_name; 84 | set => char_name = value; 85 | } 86 | 87 | public string CharClass 88 | { 89 | get => char_class; 90 | set => char_class = value; 91 | } 92 | 93 | public int CharLevel 94 | { 95 | get => char_level; 96 | set => char_level = value; 97 | } 98 | 99 | public string Greeting 100 | { 101 | get => greeting; 102 | set => greeting = value; 103 | } 104 | 105 | public int CharModel 106 | { 107 | get => char_model; 108 | set => char_model = value; 109 | } 110 | 111 | public int CharHp 112 | { 113 | get => char_HP; 114 | set => char_HP = value; 115 | } 116 | 117 | public int CharSp 118 | { 119 | get => char_SP; 120 | set => char_SP = value; 121 | } 122 | 123 | public int CharGp 124 | { 125 | get => char_GP; 126 | set => char_GP = value; 127 | } 128 | 129 | public int OnlineGodCounter 130 | { 131 | get => online_god_counter; 132 | set => online_god_counter = value; 133 | } 134 | 135 | public int OfflineGodCounter 136 | { 137 | get => offline_godCounter; 138 | set => offline_godCounter = value; 139 | } 140 | 141 | public string CharModelFile 142 | { 143 | get => charModelFile; 144 | set => charModelFile = value; 145 | } 146 | } 147 | 148 | 149 | } --------------------------------------------------------------------------------