├── .gitignore
├── GatewayServer
├── App.config
├── ClientContext.cs
├── Data
│ └── Globals.cs
├── Gateway.cs
├── GatewayServer.csproj
├── PacketProcessor.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── Services
│ ├── Launcher.cs
│ ├── Patch.cs
│ ├── Session.cs
│ └── Shard.cs
├── README.md
├── SCommon
├── Database
│ └── MSSQL.cs
├── Enumerations.cs
├── Geometry.cs
├── Logging.cs
├── Networking
│ ├── SocketContext.cs
│ └── TCPServer.cs
├── ObjectPool.cs
├── Opcode.cs
├── PooledList.cs
├── SCommon.projitems
├── SCommon.shproj
├── Security
│ ├── Blowfish.cs
│ ├── Packet.cs
│ ├── PacketReader.cs
│ ├── PacketWriter.cs
│ ├── Security.cs
│ └── TransferBuffer.cs
└── Utility.cs
├── SCore.dll
├── SCore
├── SCore.sln
└── SCore
│ ├── AssemblyInfo.cpp
│ ├── AsyncTimer.Native.cpp
│ ├── AsyncTimer.Native.h
│ ├── AsyncTimer.cpp
│ ├── AsyncTimer.h
│ ├── AutoCriticalSection.cpp
│ ├── AutoCriticalSection.h
│ ├── ReadMe.txt
│ ├── SCore.cpp
│ ├── SCore.h
│ ├── SCore.vcxproj
│ ├── SCore.vcxproj.filters
│ ├── Stdafx.cpp
│ ├── Stdafx.h
│ ├── app.ico
│ ├── app.rc
│ └── resource.h
├── SR_GameServer
├── App.config
├── ClientContext.cs
├── Data
│ ├── Enumarations.cs
│ ├── Globals.cs
│ ├── NavMesh
│ │ ├── Collision.cs
│ │ ├── JmxMesh.cs
│ │ ├── JmxNavmesh.cs
│ │ ├── JmxObj.cs
│ │ ├── JmxRes.cs
│ │ └── Structures.cs
│ ├── RefData
│ │ ├── RefCharGen.cs
│ │ ├── RefDropGold.cs
│ │ ├── RefFmnTidGroupMap.cs
│ │ ├── RefLevel.cs
│ │ ├── RefObj.cs
│ │ ├── RefRegion.cs
│ │ ├── RefShop.cs
│ │ ├── RefSkill.cs
│ │ ├── RefTeleport.cs
│ │ └── Tab_Ref.cs
│ └── Structures.cs
├── Enumarations.cs
├── Formula.cs
├── GObj.cs
├── GObjChar.cs
├── GObjItem.cs
├── GObjMob.cs
├── GObjNPC.cs
├── GameWorld
│ ├── AIManager.cs
│ └── GObjUtils.cs
├── PacketProcessor.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── SQLTableMapping.cs
├── SRGame.cs
├── SR_GameServer.csproj
├── Services
│ └── UniqueID.cs
└── Structures.cs
├── SharpDX.dll
├── SilkroadProject.sln
└── clipper_library.dll
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | Output/
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | build/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opensdf
80 | *.sdf
81 | *.cachefile
82 |
83 | # Visual Studio profiler
84 | *.psess
85 | *.vsp
86 | *.vspx
87 |
88 | # TFS 2012 Local Workspace
89 | $tf/
90 |
91 | # Guidance Automation Toolkit
92 | *.gpState
93 |
94 | # ReSharper is a .NET coding add-in
95 | _ReSharper*/
96 | *.[Rr]e[Ss]harper
97 | *.DotSettings.user
98 |
99 | # JustCode is a .NET coding add-in
100 | .JustCode
101 |
102 | # TeamCity is a build add-in
103 | _TeamCity*
104 |
105 | # DotCover is a Code Coverage Tool
106 | *.dotCover
107 |
108 | # NCrunch
109 | _NCrunch_*
110 | .*crunch*.local.xml
111 |
112 | # MightyMoose
113 | *.mm.*
114 | AutoTest.Net/
115 |
116 | # Web workbench (sass)
117 | .sass-cache/
118 |
119 | # Installshield output folder
120 | [Ee]xpress/
121 |
122 | # DocProject is a documentation generator add-in
123 | DocProject/buildhelp/
124 | DocProject/Help/*.HxT
125 | DocProject/Help/*.HxC
126 | DocProject/Help/*.hhc
127 | DocProject/Help/*.hhk
128 | DocProject/Help/*.hhp
129 | DocProject/Help/Html2
130 | DocProject/Help/html
131 |
132 | # Click-Once directory
133 | publish/
134 |
135 | # Publish Web Output
136 | *.[Pp]ublish.xml
137 | *.azurePubxml
138 | ## TODO: Comment the next line if you want to checkin your
139 | ## web deploy settings but do note that will include unencrypted
140 | ## passwords
141 | #*.pubxml
142 |
143 | *.publishproj
144 |
145 | # NuGet Packages
146 | *.nupkg
147 | # The packages folder can be ignored because of Package Restore
148 | **/packages/*
149 | # except build/, which is used as an MSBuild target.
150 | !**/packages/build/
151 | # Uncomment if necessary however generally it will be regenerated when needed
152 | #!**/packages/repositories.config
153 |
154 | # Windows Azure Build Output
155 | csx/
156 | *.build.csdef
157 |
158 | # Windows Store app package directory
159 | AppPackages/
160 |
161 | # Visual Studio cache files
162 | # files ending in .cache can be ignored
163 | *.[Cc]ache
164 | # but keep track of directories ending in .cache
165 | !*.[Cc]ache/
166 |
167 | # Others
168 | ClientBin/
169 | [Ss]tyle[Cc]op.*
170 | ~$*
171 | *~
172 | *.dbmdl
173 | *.dbproj.schemaview
174 | *.pfx
175 | *.publishsettings
176 | node_modules/
177 | orleans.codegen.cs
178 |
179 | # RIA/Silverlight projects
180 | Generated_Code/
181 |
182 | # Backup & report files from converting an old project file
183 | # to a newer Visual Studio version. Backup files are not needed,
184 | # because we have git ;-)
185 | _UpgradeReport_Files/
186 | Backup*/
187 | UpgradeLog*.XML
188 | UpgradeLog*.htm
189 |
190 | # SQL Server files
191 | *.mdf
192 | *.ldf
193 |
194 | # Business Intelligence projects
195 | *.rdl.data
196 | *.bim.layout
197 | *.bim_*.settings
198 |
199 | # Microsoft Fakes
200 | FakesAssemblies/
201 |
202 | # Node.js Tools for Visual Studio
203 | .ntvs_analysis.dat
204 |
205 | # Visual Studio 6 build log
206 | *.plg
207 |
208 | # Visual Studio 6 workspace options file
209 | *.opt
210 |
211 | # LightSwitch generated files
212 | GeneratedArtifacts/
213 | _Pvt_Extensions/
214 | ModelManifest.xml
215 | *.opendb
216 | *.metagen
217 |
--------------------------------------------------------------------------------
/GatewayServer/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/GatewayServer/ClientContext.cs:
--------------------------------------------------------------------------------
1 | namespace GatewayServer
2 | {
3 | using System;
4 | using System.Threading.Tasks;
5 |
6 | using SCore;
7 |
8 | using SCommon.Security;
9 | using SCommon.Networking;
10 |
11 | public class ClientContext : IDisposable
12 | {
13 | #region Private Properties and Fields
14 |
15 | ///
16 | /// Stores if the class has disposed
17 | ///
18 | private bool m_blDisposed;
19 |
20 | ///
21 | ///
22 | ///
23 | private bool m_blDisconnected;
24 |
25 | ///
26 | /// The context.
27 | ///
28 | private SocketContext m_SocketContext;
29 |
30 | ///
31 | /// The ping timer.
32 | ///
33 | private AsyncTimer m_PingTimer;
34 |
35 | #endregion
36 |
37 | #region Constructors & Destructors
38 |
39 | public ClientContext()
40 | {
41 | m_PingTimer = new AsyncTimer(PingTimerCallback);
42 | m_blDisconnected = false;
43 | }
44 |
45 | public ClientContext(SocketContext context)
46 | : this ()
47 | {
48 | m_SocketContext = context;
49 | }
50 |
51 | ~ClientContext()
52 | {
53 | Dispose(false);
54 | }
55 |
56 | public void Dispose()
57 | {
58 | Dispose(true);
59 | GC.SuppressFinalize(this);
60 | }
61 |
62 | protected virtual void Dispose(bool disposing)
63 | {
64 | if (!m_blDisposed)
65 | {
66 | if (disposing)
67 | {
68 | //
69 | }
70 | m_PingTimer = null;
71 | m_blDisposed = true;
72 | }
73 | }
74 | #endregion
75 |
76 | #region Public Properties and Fields
77 |
78 | ///
79 | /// Gets the context.
80 | ///
81 | public SocketContext SocketContext => m_SocketContext;
82 |
83 | ///
84 | /// Gets the ping timer.
85 | ///
86 | public AsyncTimer PingTimer => m_PingTimer;
87 |
88 | ///
89 | /// Gets or sets the last ping tick.
90 | ///
91 | public int LastPingTick { get; set; }
92 |
93 | ///
94 | /// Gets or sets the last server list send tick
95 | ///
96 | public int LastServerListTick { get; set; } = Environment.TickCount;
97 |
98 | #endregion
99 |
100 | #region Public Methods
101 |
102 | ///
103 | /// Sets the socket context.
104 | ///
105 | /// The socket context.
106 | public void SetContext(SocketContext context)
107 | {
108 | m_SocketContext = context;
109 | m_blDisconnected = false;
110 | }
111 |
112 | #pragma warning disable 1998, 4014
113 | public async Task ProcessLoginResult(Services._shard_item shard, string id, string password)
114 | {
115 | using (var reader = await Data.Globals.AccountDB.ExecuteReaderAsync("exec _CertifyTB_User '{0}', '{1}'", id, password))
116 | {
117 | await reader.ReadAsync();
118 |
119 | Packet resp = new Packet(SCommon.Opcode.Gateway.Response.LOGIN);
120 |
121 | int type = await reader.GetFieldValueAsync(0);
122 | switch (type)
123 | {
124 | case 0:
125 | {
126 | int sid = await reader.GetFieldValueAsync(1);
127 | byte sec_content = await reader.GetFieldValueAsync(2);
128 | int session_id = -1;
129 | lock (shard.m_lock)
130 | {
131 | if (shard.CurrentUsers < shard.MaxUsers)
132 | session_id = Services.Session.Generate();
133 | }
134 |
135 | if (session_id != -1)
136 | {
137 | Data.Globals.GlobalDB.ExecuteCommandAsync("INSERT INTO _ActiveSessions (UserSID, SessionID, Processed) VALUES ({0}, {1}, 0)", sid, session_id);
138 |
139 | resp.WriteByte(1);
140 | resp.WriteInt32(session_id);
141 | resp.WriteAscii(Data.Globals.GetConfigValue("GameServerIPAddress"));
142 | resp.WriteUInt16(Data.Globals.GetConfigValue("GameServerPort"));
143 | }
144 | else
145 | {
146 | resp.WriteByte(2);
147 | resp.WriteByte(5);
148 | }
149 | }
150 | break;
151 | case 1:
152 | {
153 | int sid = await reader.GetFieldValueAsync(1);
154 | string ban_reason = await reader.GetFieldValueAsync(2);
155 | DateTime ban_endTime = await reader.GetFieldValueAsync(3);
156 |
157 | resp.WriteByte(2);
158 | resp.WriteByte(2);
159 | resp.WriteByte(1);
160 | resp.WriteAscii(ban_reason);
161 | resp.WriteUInt16(ban_endTime.Year);
162 | resp.WriteUInt16(ban_endTime.Month);
163 | resp.WriteUInt16(ban_endTime.Day);
164 | resp.WriteUInt16(ban_endTime.Hour);
165 | resp.WriteUInt16(ban_endTime.Minute);
166 | resp.WriteUInt16(ban_endTime.Second);
167 | resp.WriteInt32(ban_endTime.Millisecond);
168 | }
169 | break;
170 | case 2:
171 | {
172 | resp.WriteByte(2);
173 | resp.WriteByte(1);
174 |
175 | if (Data.Globals.WrongPasswordTries.ContainsKey(id))
176 | {
177 | var wrong = Data.Globals.WrongPasswordTries[id];
178 |
179 | resp.WriteInt32(++wrong.Tries);
180 |
181 | wrong.LastTick = Environment.TickCount;
182 | Data.Globals.WrongPasswordTries[id] = wrong;
183 | }
184 | else
185 | {
186 | var wrong = new Data._wrongpass_item
187 | {
188 | LastTick = Environment.TickCount,
189 | Tries = 1
190 | };
191 | Data.Globals.WrongPasswordTries.Add(id, wrong);
192 |
193 | resp.WriteInt32(1);
194 | }
195 |
196 | resp.WriteInt32(Data.Globals.MAX_WRONG_PASSWORD);
197 | }
198 | break;
199 | case 3:
200 | {
201 | //already in game packet
202 | }
203 | break;
204 | }
205 |
206 | m_SocketContext.Send(resp);
207 | Disconnect();
208 | }
209 | }
210 |
211 | ///
212 | /// Disconnects the client
213 | ///
214 | /// if true, the function won't call Socket.Disconnect
215 | public void Disconnect(bool disconnecting = false)
216 | {
217 | lock (this)
218 | {
219 | if (!disconnecting)
220 | m_SocketContext.Disconnect();
221 |
222 | if (!m_blDisconnected)
223 | {
224 | if (m_PingTimer.IsRunning)
225 | m_PingTimer.Stop();
226 | m_blDisconnected = true;
227 | }
228 | }
229 | }
230 |
231 | #endregion
232 |
233 | #region Private Methods
234 |
235 | ///
236 | /// The ping timer's callback.
237 | ///
238 | /// The sender.
239 | /// The state.
240 | private void PingTimerCallback(object sender, object state)
241 | {
242 | if (Environment.TickCount - LastPingTick >= 10000)
243 | {
244 | LastPingTick = Environment.TickCount;
245 | Console.WriteLine("client timeout, disconnecting (last: {0}, elapsed: {1})", LastPingTick, Environment.TickCount - LastPingTick);
246 | m_PingTimer.Reset(-1, 0);
247 | Disconnect();
248 | }
249 | }
250 |
251 | #endregion
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/GatewayServer/Data/Globals.cs:
--------------------------------------------------------------------------------
1 | namespace GatewayServer.Data
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | using SCommon.Database;
7 |
8 | public struct _wrongpass_item
9 | {
10 | public int Tries;
11 | public int LastTick;
12 | }
13 |
14 | internal static class Globals
15 | {
16 | public const int MAX_WRONG_PASSWORD = 3;
17 |
18 | public static Gateway GatewayService;
19 | public static Dictionary Config;
20 | public static Dictionary WrongPasswordTries;
21 | public static MSSQL GlobalDB;
22 | public static MSSQL AccountDB;
23 |
24 | public static bool ConnectGlobalDB()
25 | {
26 | try
27 | {
28 | GlobalDB = new MSSQL("SR_Global Connection String");
29 | return true;
30 | }
31 | #if DEBUG
32 | catch (Exception ex)
33 | #else
34 | catch (Exception)
35 | #endif
36 | {
37 | #if DEBUG
38 | Console.WriteLine(ex);
39 | #endif
40 | return false;
41 | }
42 | }
43 |
44 | public static bool ConnectAccountDB()
45 | {
46 | try
47 | {
48 | AccountDB = new MSSQL("SR_Account Connection String");
49 | return true;
50 | }
51 | #if DEBUG
52 | catch (Exception ex)
53 | #else
54 | catch (Exception)
55 | #endif
56 | {
57 | #if DEBUG
58 | Console.WriteLine(ex);
59 | #endif
60 | return false;
61 | }
62 | }
63 |
64 | public static bool LoadConfigTable()
65 | {
66 | try
67 | {
68 | Config = new Dictionary();
69 | using (var reader = GlobalDB.ExecuteReader("SELECT * FROM _ServerConfig"))
70 | {
71 | while (reader.Read())
72 | Data.Globals.Config.Add(Convert.ToString(reader["Key"]), Convert.ToString(reader["Value"]));
73 | }
74 | return true;
75 | }
76 | #if DEBUG
77 | catch (Exception ex)
78 | #else
79 | catch (Exception)
80 | #endif
81 | {
82 | #if DEBUG
83 | Console.WriteLine(ex);
84 | #endif
85 | return false;
86 | }
87 | }
88 |
89 | public static T GetConfigValue(string key)
90 | {
91 | return (T)Convert.ChangeType(Config[key], typeof(T));
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/GatewayServer/Gateway.cs:
--------------------------------------------------------------------------------
1 | namespace GatewayServer
2 | {
3 | using System;
4 | using System.Threading;
5 |
6 | using SCommon;
7 | using SCommon.Networking;
8 | using SCommon.Security;
9 |
10 | internal class Gateway
11 | {
12 | #region Private Properties and Fields
13 |
14 | ///
15 | /// The server's ip address
16 | ///
17 | private string m_IPAddress;
18 |
19 | ///
20 | /// The server's port
21 | ///
22 | private int m_Port;
23 |
24 | ///
25 | /// The tcp server
26 | ///
27 | private TCPServer m_Server;
28 |
29 | ///
30 | /// The pool for class
31 | ///
32 | private ObjectPool m_ClientContextPool;
33 |
34 | #endregion
35 |
36 | #region Constructors and Destructors
37 |
38 | public Gateway(string ip, int port)
39 | {
40 | m_IPAddress = ip;
41 | m_Port = port;
42 | m_ClientContextPool = new ObjectPool(() => new ClientContext(), () => m_ClientContextPool.Count > 200);
43 |
44 | Services.Patch.Initialize();
45 | Services.Shard.Initialize();
46 | Services.Launcher.Initialize();
47 | Services.Session.Initialize();
48 | }
49 |
50 | #endregion
51 |
52 | #region Public Properties and Fileds
53 |
54 | public int ActiveConnectionCount => Interlocked.Exchange(ref m_Server.m_ConnectionCount, m_Server.m_ConnectionCount);
55 |
56 | #endregion
57 |
58 | #region Public Methods
59 |
60 | ///
61 | /// Updates the gateway service's state
62 | ///
63 | ///
64 | public void UpdateServiceState(bool state)
65 | {
66 | if (state)
67 | {
68 | //initialize the server and start the tcp service
69 | if (m_Server == null)
70 | {
71 | m_Server = new TCPServer(m_IPAddress, m_Port, SecurityFlags.Blowfish | SecurityFlags.SecurityBytes);
72 | TCPServer.OnNewConnection += Gateway_NewConnection;
73 | SocketContext.OnPacketReceived += SocketContext_PacketReceived;
74 | SocketContext.OnLostConnection += SocketContext_ConnectionLost;
75 | m_Server.StartService();
76 | }
77 | }
78 | else
79 | {
80 | //
81 | }
82 | }
83 |
84 | #endregion
85 |
86 | #region Private Methods
87 |
88 | ///
89 | /// The OnNewConnection event.
90 | ///
91 | /// The client context.
92 | /// The socket context.
93 | private void Gateway_NewConnection(object sender, SocketContext context)
94 | {
95 | #if DEBUG
96 | Logging.Log()(String.Format("A new connection has arrived. (SocketContext Hash Code:{0:X8})", context.GetHashCode()), LogLevel.Info);
97 | #endif
98 | ClientContext client = m_ClientContextPool.GetObject();
99 | client.SetContext(context);
100 |
101 | context.SetContext(client);
102 | }
103 |
104 | ///
105 | /// The OnPacketReceived event.
106 | ///
107 | /// The client context.
108 | /// The socket context.
109 | private void SocketContext_PacketReceived(object sender, Packet packet)
110 | {
111 | Func fn;
112 | ClientContext client = (ClientContext)((SocketContext)sender).Context;
113 |
114 | client.LastPingTick = Environment.TickCount;
115 |
116 | if (PacketProcessor.OpcodeMap[packet.Opcode] != null)
117 | fn = PacketProcessor.OpcodeMap[packet.Opcode];
118 | else
119 | fn = PacketProcessor.OpcodeMap[0];
120 |
121 | if (!fn(client, packet))
122 | client.Disconnect();
123 | }
124 |
125 | ///
126 | /// The OnLostConnection event.
127 | ///
128 | /// The client context.
129 | /// The event args.
130 | private void SocketContext_ConnectionLost(object sender, EventArgs args)
131 | {
132 | #if DEBUG
133 | Logging.Log()(String.Format("A connection has dropped. (SocketContext Hash Code:{0:X8})", sender.GetHashCode()), LogLevel.Info);
134 | #endif
135 | ClientContext client = (ClientContext)((SocketContext)sender).Context;
136 | client.Disconnect(true);
137 | m_ClientContextPool.PutObject(client);
138 | }
139 |
140 | #endregion
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/GatewayServer/GatewayServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {422E556D-B2C7-4607-A485-3B1C6EED41EB}
8 | Exe
9 | Properties
10 | GatewayServer
11 | GatewayServer
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | ..\Output\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | ..\Output\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 | true
38 | bin\x86\Debug\
39 | DEBUG;TRACE
40 | full
41 | x86
42 | prompt
43 | MinimumRecommendedRules.ruleset
44 | true
45 |
46 |
47 | bin\x86\Release\
48 | TRACE
49 | true
50 | pdbonly
51 | x86
52 | prompt
53 | MinimumRecommendedRules.ruleset
54 | true
55 | true
56 |
57 |
58 | true
59 | bin\x64\Debug\
60 | DEBUG;TRACE
61 | true
62 | full
63 | x64
64 | prompt
65 | MinimumRecommendedRules.ruleset
66 | true
67 |
68 |
69 | bin\x64\Release\
70 | TRACE
71 | true
72 | pdbonly
73 | x64
74 | prompt
75 | MinimumRecommendedRules.ruleset
76 | true
77 |
78 |
79 |
80 | ..\clipper_library.dll
81 |
82 |
83 | ..\..\..\..\..\Downloads\LeagueSharp\System\SharpDX.dll
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | {a0e9c09c-cc53-474f-bdd5-a641f57e2215}
112 | SCore
113 |
114 |
115 |
116 |
117 |
124 |
--------------------------------------------------------------------------------
/GatewayServer/PacketProcessor.cs:
--------------------------------------------------------------------------------
1 | namespace GatewayServer
2 | {
3 | using System;
4 | using System.Linq;
5 |
6 | using SCommon.Security;
7 |
8 | using Opcode = SCommon.Opcode;
9 |
10 | public static class PacketProcessor
11 | {
12 | #region Private Properties and Fields
13 |
14 | ///
15 | /// The opcode map.
16 | ///
17 | private static Func[] s_OpcodeMap = new Func[256 * 256];
18 |
19 | #endregion
20 |
21 | #region Public Properties and Fields
22 |
23 | ///
24 | /// Gets the opcode map.
25 | ///
26 | public static Func[] OpcodeMap => s_OpcodeMap;
27 |
28 | #endregion
29 |
30 | #region Public Methods
31 |
32 | ///
33 | /// Fills the opcode map.
34 | ///
35 | public static void FillTable()
36 | {
37 | s_OpcodeMap[0] = Unhandled;
38 | s_OpcodeMap[Opcode.General.PING] = Ping;
39 | s_OpcodeMap[Opcode.General.IDENTITY] = Identity;
40 | s_OpcodeMap[Opcode.Gateway.Request.PATCH] = Patch;
41 | s_OpcodeMap[Opcode.Gateway.Request.SERVERLIST] = ServerList;
42 | s_OpcodeMap[Opcode.Gateway.Request.LOGIN] = Login;
43 | s_OpcodeMap[Opcode.Gateway.Request.LAUNCHER] = Launcher;
44 | }
45 |
46 | #endregion
47 |
48 | #region Private Methods
49 |
50 | private static bool Unhandled(ClientContext Me, Packet packet)
51 | {
52 | Console.WriteLine("Unhandled msg 0x{0:X4}", packet.Opcode);
53 | #if DEBUG
54 | return true;
55 | #endif
56 | return false;
57 | }
58 |
59 | private static bool Ping(ClientContext Me, Packet packet)
60 | {
61 | return true;
62 | }
63 |
64 | private static bool Identity(ClientContext Me, Packet packet)
65 | {
66 | if (packet.ReadAscii() == "SR_Client")
67 | {
68 | Packet resp = new Packet(Opcode.General.IDENTITY);
69 | resp.WriteAscii("GatewayServer");
70 | resp.WriteByte(0);
71 | Me.SocketContext.Send(resp);
72 |
73 | return true;
74 | }
75 |
76 | return false;
77 | }
78 |
79 | private static bool Patch(ClientContext Me, Packet packet)
80 | {
81 | bool ret = true;
82 |
83 | byte locale = packet.ReadByte();
84 | string identity_name = packet.ReadAscii();
85 | uint version = packet.ReadUInt32();
86 |
87 | Packet seed1 = new Packet(Opcode.General.SEED_1, false, true, new byte[] { 0x01, 0x00, 0x01, 0x47, 0x01, 0x05, 0x00, 0x00, 0x00, 0x02 });
88 | Packet seed2 = new Packet(Opcode.General.SEED_2, false, true, new byte[] { 0x03, 0x00, 0x02, 0x00, 0x02 });
89 |
90 | Me.SocketContext.EnqueuePacket(seed1);
91 | Me.SocketContext.EnqueuePacket(seed2);
92 |
93 | if (identity_name == "SR_Client")
94 | {
95 | uint current_version = Data.Globals.GetConfigValue("CurrentVersion");
96 | uint latest_version = Data.Globals.GetConfigValue("LatestVersion");
97 |
98 | Packet resp = new Packet(Opcode.Gateway.Response.PATCH, false, true);
99 |
100 | if (version == current_version) //no patches
101 | resp.WriteByte(1);
102 | else
103 | {
104 | resp.WriteByte(2);
105 |
106 | if (version < latest_version) //too old client, cannot update
107 | resp.WriteByte(5);
108 | else if (version > current_version) //too new client ? its illegal operation !
109 | {
110 | resp.WriteByte(1);
111 | ret = false;
112 | Console.WriteLine("Illegal operation ! Current Version: {0}, Requested: {1}", current_version, version);
113 | }
114 | else //send patches
115 | {
116 | resp.WriteByte(2);
117 | resp.WriteAscii(Data.Globals.GetConfigValue("DownloadServerIPAddress"));
118 | resp.WriteUInt32(Data.Globals.GetConfigValue("DownloadServerPort"));
119 | resp.WriteUInt32(current_version);
120 | foreach(var file in Services.Patch.Items)
121 | {
122 | resp.WriteByte(1);
123 | resp.WriteUInt32(file.ID);
124 | resp.WriteAscii(file.FileName);
125 | resp.WriteAscii(file.Path);
126 | resp.WriteUInt32(file.FileSize);
127 | resp.WriteByte(file.ToBePacked);
128 | }
129 | resp.WriteByte(0);
130 | }
131 | }
132 |
133 | Me.SocketContext.EnqueuePacket(resp);
134 | Me.SocketContext.ProcessSendQueue();
135 | }
136 | else
137 | return false;
138 |
139 | if (ret)
140 | Me.PingTimer.Start(10000, 10000);
141 |
142 | return ret;
143 | }
144 |
145 | private static bool ServerList(ClientContext Me, Packet packet)
146 | {
147 | if (Environment.TickCount - Me.LastServerListTick >= 4000)
148 | {
149 | Packet resp = new Packet(Opcode.Gateway.Response.SERVERLIST);
150 | resp.WriteByte(1);
151 | resp.WriteByte(0x15);
152 | resp.WriteAscii("SRO_Global_TestBed");
153 | resp.WriteByte(0);
154 | foreach(var shard in Services.Shard.Items)
155 | {
156 | resp.WriteUInt8(1);
157 | resp.WriteUInt16(shard.ID);
158 | resp.WriteAscii(shard.Name);
159 | resp.WriteUInt16(shard.CurrentUsers);
160 | resp.WriteUInt16(shard.MaxUsers);
161 | resp.WriteUInt8(shard.State);
162 | }
163 | resp.WriteByte(0);
164 |
165 | Me.SocketContext.Send(resp);
166 | return true;
167 | }
168 |
169 | //too much requests, disconnect the client
170 | return false;
171 | }
172 |
173 | #pragma warning disable 4014
174 | private static bool Login(ClientContext Me, Packet packet)
175 | {
176 | byte locale = packet.ReadByte();
177 | string id = packet.ReadAscii();
178 | string password = SCommon.Utility.MD5Hash(packet.ReadAscii(), true);
179 | ushort server = packet.ReadUInt16();
180 | Data._wrongpass_item wrong;
181 |
182 | Packet resp = new Packet(Opcode.Gateway.Response.LOGIN);
183 |
184 | if (Services.Shard.Items.Exists(p => p.ID == server))
185 | {
186 | var shard = Services.Shard.Items.FirstOrDefault(p => p.ID == server);
187 | resp.WriteByte(2);
188 | if (shard.State != 1)
189 | {
190 | resp.WriteByte(2);
191 | resp.WriteByte(2);
192 | }
193 | else if (shard.ContentID != locale)
194 | {
195 | resp.WriteByte(7);
196 | }
197 | else if (id.Contains('\''))
198 | {
199 | resp.WriteByte(6);
200 | }
201 | else if (Data.Globals.WrongPasswordTries.ContainsKey(id) && (wrong = Data.Globals.WrongPasswordTries[id]).Tries >= Data.Globals.MAX_WRONG_PASSWORD)
202 | {
203 | if (Environment.TickCount - wrong.LastTick < 5 * 60 * 1000)
204 | {
205 | resp.WriteByte(1);
206 | resp.WriteInt32(wrong.Tries);
207 | resp.WriteInt32(Data.Globals.MAX_WRONG_PASSWORD);
208 | }
209 | else
210 | Data.Globals.WrongPasswordTries.Remove(id);
211 | }
212 | else
213 | {
214 | Me.ProcessLoginResult(shard, id, password);
215 | return true;
216 | }
217 |
218 | Me.SocketContext.Send(resp);
219 | }
220 | else
221 | return false;
222 |
223 | return true;
224 | }
225 |
226 | private static bool Launcher(ClientContext Me, Packet packet)
227 | {
228 | byte locale = packet.ReadByte();
229 | byte written_news = 0;
230 |
231 | Packet resp = new Packet(Opcode.Gateway.Response.LAUNCHER, false, true);
232 | resp.WriteByte(0); //news count
233 | foreach(var news in Services.Launcher.Items)
234 | {
235 | if (news.ContentID == locale)
236 | {
237 | resp.WriteAscii(news.Subject);
238 | resp.WriteAscii(news.Article);
239 | resp.WriteUInt16(news.EditDate.Year);
240 | resp.WriteUInt16(news.EditDate.Month);
241 | resp.WriteUInt16(news.EditDate.Day);
242 | resp.WriteUInt16(news.EditDate.Hour);
243 | resp.WriteUInt16(news.EditDate.Minute);
244 | resp.WriteUInt16(news.EditDate.Second);
245 | resp.WriteUInt32(news.EditDate.Millisecond);
246 |
247 | written_news++;
248 | }
249 | }
250 | resp.ReWriteAt(0, written_news);
251 |
252 | Me.SocketContext.Send(resp);
253 |
254 | return true;
255 | }
256 |
257 | #endregion
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/GatewayServer/Program.cs:
--------------------------------------------------------------------------------
1 | namespace GatewayServer
2 | {
3 | using System;
4 | using System.Threading;
5 | using System.Collections.Generic;
6 |
7 | using SCore;
8 |
9 | using SCommon;
10 |
11 | internal class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | #region Assert Debug Mode
16 | #if DEBUG
17 | Logging.Log()("Debug mode is active", LogLevel.Info);
18 | #endif
19 | #endregion
20 |
21 | #region Initialize Services
22 |
23 | TimerService.Initialize();
24 | Logging.Log()("Timer service has initialized", LogLevel.Success);
25 |
26 | PacketProcessor.FillTable();
27 | Logging.Log()("Packet Processor has initialized", LogLevel.Success);
28 |
29 | #endregion
30 |
31 | #region Connect to Database Services
32 |
33 | if (Data.Globals.ConnectGlobalDB())
34 | Logging.Log()("Connected to global db", LogLevel.Notify);
35 | else
36 | Logging.Log()("Cannot connect to global db", LogLevel.Error);
37 |
38 | if (Data.Globals.ConnectAccountDB())
39 | Logging.Log()("Connected to account db", LogLevel.Notify);
40 | else
41 | Logging.Log()("Cannot connect to account db", LogLevel.Error);
42 |
43 | //truncate the sessions
44 | Data.Globals.GlobalDB.ExecuteCommand("TRUNCATE TABLE _ActiveSessions");
45 |
46 | #endregion
47 |
48 | #region Load Configs
49 |
50 | if (Data.Globals.LoadConfigTable())
51 | Logging.Log()("Server config has loaded", LogLevel.Notify);
52 | else
53 | Logging.Log()("Cannot load server config", LogLevel.Error);
54 |
55 | Data.Globals.WrongPasswordTries = new Dictionary();
56 |
57 | #endregion
58 |
59 | #region Start Service
60 |
61 | Data.Globals.GatewayService = new Gateway(Data.Globals.GetConfigValue("GatewayServerIPAddress"), Data.Globals.GetConfigValue("GatewayServerPort"));
62 | Data.Globals.GatewayService.UpdateServiceState(true);
63 | Logging.Log()("Gateway Service has started", LogLevel.Info);
64 |
65 | #endregion
66 |
67 | #region Start GC CollectorThread
68 |
69 | new Thread(new ThreadStart(() =>
70 | {
71 | while (true)
72 | {
73 | GC.Collect();
74 | Thread.Sleep(10000);
75 | }
76 | })).Start();
77 |
78 | #endregion
79 |
80 | #region Console command helper
81 |
82 | while (true)
83 | {
84 | Console.Write("gateway@{0}:~# ", Data.Globals.GetConfigValue("GatewayServerIPAddress"));
85 | var commands = Console.ReadLine().ToLower().Split(' ');
86 | switch(commands[0])
87 | {
88 | case "exit":
89 | Environment.Exit(0);
90 | break;
91 | case "clear":
92 | Console.Clear();
93 | break;
94 | case "enablepacketlogging":
95 | Logging.EnablePacketLogging = Convert.ToBoolean(commands[1]);
96 | Logging.Log()(String.Format("Set EnablePacketLogging = {0}", Logging.EnablePacketLogging ? "TRUE" : "FALSE"), LogLevel.Success);
97 | break;
98 | case "connectioncount":
99 | Logging.Log()(String.Format("Current Active Connections Count is {0}", Data.Globals.GatewayService.ActiveConnectionCount), LogLevel.Info);
100 | break;
101 | }
102 | Thread.Sleep(1);
103 | }
104 |
105 | #endregion
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/GatewayServer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("GatewayServer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("GatewayServer")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("422e556d-b2c7-4607-a485-3b1c6eed41eb")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/GatewayServer/Services/Launcher.cs:
--------------------------------------------------------------------------------
1 | namespace GatewayServer.Services
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | ///
7 | /// The launcher news item structure
8 | ///
9 | public struct _news_item
10 | {
11 | public uint ID;
12 | public byte ContentID;
13 | public string Subject;
14 | public string Article;
15 | public DateTime EditDate;
16 | }
17 |
18 | ///
19 | /// The launcher service class.
20 | ///
21 | public static class Launcher
22 | {
23 | #region Private Properties and Fields
24 |
25 | ///
26 | /// The launcher news items.
27 | ///
28 | private static List<_news_item> s_Items;
29 |
30 | #endregion
31 |
32 | #region Initializer Method
33 |
34 | public static void Initialize()
35 | {
36 | s_Items = new List<_news_item>();
37 | using (var reader = Data.Globals.AccountDB.ExecuteReader("SELECT TOP 4 * FROM _Notice ORDER BY EditDate DESC"))
38 | {
39 | while(reader.Read())
40 | {
41 | _news_item item = new _news_item
42 | {
43 | ID = (uint)(int)reader["ID"],
44 | ContentID = (byte)reader["ContentID"],
45 | Subject = (string)reader["Subject"],
46 | Article = (string)reader["Article"],
47 | EditDate = (DateTime)reader["EditDate"]
48 | };
49 |
50 | s_Items.Add(item);
51 | }
52 | }
53 | }
54 |
55 | #endregion
56 |
57 | #region Public Properties and Fields
58 |
59 | ///
60 | /// Gets the launcher news item list
61 | ///
62 | public static List<_news_item> Items => s_Items;
63 |
64 | #endregion
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/GatewayServer/Services/Patch.cs:
--------------------------------------------------------------------------------
1 | namespace GatewayServer.Services
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | ///
7 | /// The patch item structure
8 | ///
9 | public struct _patch_item
10 | {
11 | public uint ID;
12 | public uint Version;
13 | public uint ModuleID;
14 | public string FileName;
15 | public string Path;
16 | public uint FileSize;
17 | public byte FileType;
18 | public uint FileTypeVersion;
19 | public bool ToBePacked;
20 | public DateTime TimeModified;
21 | public bool IsValid;
22 | }
23 |
24 | ///
25 | /// The patch service class
26 | ///
27 | public static class Patch
28 | {
29 | #region Private Properties and Fields
30 |
31 | ///
32 | /// The patch file items.
33 | ///
34 | private static List<_patch_item> s_Items;
35 |
36 | #endregion
37 |
38 | #region Initializer Method
39 |
40 | public static void Initialize()
41 | {
42 | s_Items = new List<_patch_item>();
43 | using (var reader = Data.Globals.AccountDB.ExecuteReader("SELECT * FROM _ModuleVersionFile WHERE nVersion > {0} AND nValid = 1 AND nModuleID = '{1}' ORDER BY nID", Data.Globals.GetConfigValue("LatestVersion"), 9))
44 | {
45 | while(reader.Read())
46 | {
47 | _patch_item item = new _patch_item
48 | {
49 | ID = (uint)reader["nID"],
50 | Version = (uint)reader["nVersion"],
51 | ModuleID = (uint)reader["nModuleID"],
52 | FileName = (string)reader["szFilename"],
53 | Path = ((string)reader["szPath"]).Replace(".", ""),
54 | FileSize = (uint)reader["nFileSize"],
55 | FileType = (byte)reader["nFileType"],
56 | FileTypeVersion = (uint)reader["nFileTypeVersion"],
57 | ToBePacked = Convert.ToBoolean(reader["nToBePacked"]),
58 | TimeModified = (DateTime)reader["timeModified"],
59 | IsValid = Convert.ToBoolean(reader["nValid"])
60 | };
61 |
62 | s_Items.Add(item);
63 | }
64 | }
65 | }
66 |
67 | #endregion
68 |
69 | #region Public Properties and Fields
70 |
71 | ///
72 | /// Gets the patch file items list.
73 | ///
74 | public static List<_patch_item> Items => s_Items;
75 |
76 | #endregion
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/GatewayServer/Services/Session.cs:
--------------------------------------------------------------------------------
1 | namespace GatewayServer.Services
2 | {
3 | using System.Threading;
4 |
5 | public static class Session
6 | {
7 | #region Private Properties and Fields
8 |
9 | ///
10 | /// Stores the last generated session id
11 | ///
12 | private static volatile int s_LastSessionID;
13 |
14 | #endregion
15 |
16 | #region Initializer Methods
17 |
18 | public static void Initialize()
19 | {
20 | s_LastSessionID = int.MinValue;
21 | }
22 |
23 | #endregion
24 |
25 | #region Public Methods
26 |
27 | ///
28 | /// Generates the new session id
29 | ///
30 | ///
31 | public static int Generate()
32 | {
33 | if (PreventOverflows())
34 | return int.MinValue;
35 |
36 | return Interlocked.Increment(ref s_LastSessionID);
37 | }
38 |
39 | #endregion
40 |
41 | #region Private Methods
42 |
43 | ///
44 | /// Checks for the overflows
45 | ///
46 | ///
47 | private static bool PreventOverflows()
48 | {
49 | return Interlocked.CompareExchange(ref s_LastSessionID, int.MinValue, int.MaxValue) == int.MaxValue;
50 | }
51 |
52 | #endregion
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/GatewayServer/Services/Shard.cs:
--------------------------------------------------------------------------------
1 | namespace GatewayServer.Services
2 | {
3 | using System.Collections.Generic;
4 |
5 | ///
6 | /// The shard item structure
7 | ///
8 | public struct _shard_item
9 | {
10 | public int ID;
11 | public string Name;
12 | public byte ContentID;
13 | public ushort CurrentUsers;
14 | public ushort MaxUsers;
15 | public byte State;
16 | public object m_lock;
17 | }
18 |
19 |
20 | ///
21 | /// The shard service class
22 | ///
23 | public static class Shard
24 | {
25 | #region Private Properties and Fields
26 |
27 | ///
28 | /// The shard list.
29 | ///
30 | private static List<_shard_item> s_Items;
31 |
32 | #endregion
33 |
34 | #region Initializer Method
35 |
36 | public static void Initialize()
37 | {
38 | s_Items = new List<_shard_item>();
39 | using (var reader = Data.Globals.AccountDB.ExecuteReader("SELECT * FROM _Shard"))
40 | {
41 | while(reader.Read())
42 | {
43 | _shard_item item = new _shard_item
44 | {
45 | ID = (int)reader["ID"],
46 | Name = (string)reader["Name"],
47 | ContentID = (byte)reader["ContentID"],
48 | CurrentUsers = 0,
49 | MaxUsers = (ushort)(short)reader["MaxUsers"],
50 | State = (byte)reader["State"],
51 | m_lock = new object()
52 | };
53 |
54 | s_Items.Add(item);
55 | }
56 | }
57 | }
58 |
59 | #endregion
60 |
61 | #region Public Properties and Fields
62 |
63 | ///
64 | /// Gets the shard list
65 | ///
66 | public static List<_shard_item> Items => s_Items;
67 |
68 | #endregion
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SilkroadProject
2 | Silkroad Online Emulator for Open Beta Client
3 |
4 | ### Requirements
5 | - Visual Studio 2015
6 | - Microsoft SQL Server 2008 or above
7 | - Asio 1.10.6 for SCore (our AsyncTimer uses asio)
8 |
9 | ### How To Setup Server
10 | - Restore database dumps
11 | - Edit _ServerConfig table in SR_Global
12 | - Extract your data.pk2 to data/ folder
13 | - Edit GatewayServer/Data/Globals.cs and SR_GameServer/Data/Globals.cs for connection strings
14 | - Compile project with visual studio and run
15 |
16 | ### How To Setup Client
17 | - Open Media.pk2 with pk2 extractor and export GATEIP.txt
18 | - Open GATEIP.txt with a hex editor and edit ip address (fill with zeroes remaining)
19 | - Open client with IP Input change ip address again (aka change DIVISIONINFO.txt)
20 |
21 | ### How To Contribute Project
22 | - You can make pull requests to contribute project.
23 | 1. Your code must match projects design.
24 | 2. Prevent deadlocks when interacting another client.
25 | 3. Use Interlocked operations when accessing volatile variables
26 | 4. Use async Task for heavy operations
27 | 5. Test your code carefully.
28 |
29 | ### Links for projects
30 | Description | Link
31 | ------------ | -------------
32 | Database Dumps | https://mega.nz/#!UAIRWJTK!66r4XsTFAbfazIP5CvrYqQYHGyuXpLWyaH36cNWVRRc
33 | Client | https://mega.nz/#!sRBiBaLY!RQnCfHfr8HfBIRxRJctf0-5_MVC8W8OXd51pH558mm8
34 | Client Dll (Aqua.dll) source | https://mega.nz/#!MAZQUZpY!4frt9k4PDnDVFvrV02KBbx4K0xCcnZ2aUZ5W4uSfeTo
35 |
--------------------------------------------------------------------------------
/SCommon/Database/MSSQL.cs:
--------------------------------------------------------------------------------
1 | namespace SCommon.Database
2 | {
3 | using System;
4 | using System.Data.SqlClient;
5 | using System.Threading.Tasks;
6 |
7 | public class MSSQL : IDisposable
8 | {
9 | #region Private Properties and Fields
10 |
11 | ///
12 | /// The handle
13 | ///
14 | private SqlConnection m_Connection;
15 |
16 | #endregion
17 |
18 | #region Constructors & Destructors
19 |
20 | public MSSQL(string connectionStr)
21 | {
22 | m_Connection = new SqlConnection(connectionStr);
23 | m_Connection.Open();
24 | }
25 |
26 | public MSSQL(string Server, string DBName, string UserID, string Password, bool MultipleActiveResultSets)
27 | : this(String.Format("Server={0};Database={1};User Id={2};Password={3};MultipleActiveResultSets={4}", Server, DBName, UserID, Password, MultipleActiveResultSets))
28 | {
29 |
30 | }
31 |
32 | public void Dispose()
33 | {
34 | m_Connection.Close();
35 | m_Connection.Dispose();
36 | }
37 |
38 | #endregion
39 |
40 | #region Public Methods
41 |
42 | ///
43 | /// Executes the query.
44 | ///
45 | /// The query string.
46 | /// The args.
47 | /// The number of affected rows by query execution.
48 | public int ExecuteCommand(string SQLCommand, params object[] args)
49 | {
50 | SQLCommand = ReplaceArgs(SQLCommand, args);
51 | using (var cmd = new SqlCommand(SQLCommand, m_Connection))
52 | return cmd.ExecuteNonQuery();
53 | }
54 |
55 | ///
56 | /// Executes the query as async.
57 | ///
58 | /// The query string.
59 | /// The args.
60 | /// The number of affected rows by query execution.
61 | public Task ExecuteCommandAsync(string SQLCommand, params object[] args)
62 | {
63 | SQLCommand = ReplaceArgs(SQLCommand, args);
64 | using (var cmd = new SqlCommand(SQLCommand, m_Connection))
65 | return cmd.ExecuteNonQueryAsync();
66 | }
67 |
68 | ///
69 | /// Executes query and returns the query result reader
70 | ///
71 | /// The query string.
72 | /// The args.
73 | /// returned by the query execution.
74 | public SqlDataReader ExecuteReader(string SQLCommand, params object[] args)
75 | {
76 | try
77 | {
78 | SQLCommand = ReplaceArgs(SQLCommand, args);
79 | using (var cmd = new SqlCommand(SQLCommand, m_Connection))
80 | return cmd.ExecuteReader();
81 | }
82 | catch { return null; }
83 | }
84 |
85 | ///
86 | /// Executes query as async and returns the query result reader
87 | ///
88 | /// The query string.
89 | /// The args.
90 | /// returned by the query execution.
91 | public Task ExecuteReaderAsync(string SQLCommand, params object[] args)
92 | {
93 | try
94 | {
95 | SQLCommand = ReplaceArgs(SQLCommand, args);
96 | using (var cmd = new SqlCommand(SQLCommand, m_Connection))
97 | return cmd.ExecuteReaderAsync();
98 | }
99 | catch { return null; }
100 | }
101 |
102 | ///
103 | /// Executes query and gets the result of query (row 0 column 0)
104 | ///
105 | /// The return type.
106 | /// The query string.
107 | /// The args.
108 | /// Data returned by query
109 | public T Result(string SQLCommand, params object[] args)
110 | {
111 | try
112 | {
113 | SQLCommand = ReplaceArgs(SQLCommand, args);
114 | using (var cmd = new SqlCommand(SQLCommand, m_Connection))
115 | return (T)cmd.ExecuteScalar();
116 | }
117 | catch { return default(T); }
118 | }
119 |
120 | ///
121 | /// Executes query as async and gets the result of query (row 0 column 0)
122 | ///
123 | /// The return type.
124 | /// The query string.
125 | /// The args.
126 | /// Data returned by query
127 | public Task