Skip to content

Commit 817e85b

Browse files
committed
init
1 parent 1b390ec commit 817e85b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3036
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

Database/index.js

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
const MongoClient = require("mongodb").MongoClient;
2+
const mongoClient = new MongoClient("mongodb://127.0.0.1:27017/");
3+
4+
class Database {
5+
constructor() {
6+
this._db = null;
7+
}
8+
9+
async connect(callback) {
10+
try {
11+
await mongoClient.connect();
12+
13+
this._db = mongoClient.db("l2db");
14+
15+
callback();
16+
} catch {
17+
throw new Error("database connected: failed");
18+
}
19+
}
20+
21+
async getAccountByLogin(login) {
22+
const user = await this._db.collection('accounts').findOne({ login });
23+
24+
if (user) {
25+
return user;
26+
} else {
27+
return null;
28+
}
29+
}
30+
31+
async addCharacter(character) {
32+
await this._db.collection('characters').insertOne(character);
33+
}
34+
35+
async getCharactersByLogin(login) {
36+
return await this._db.collection('characters').find({ login }).toArray();
37+
}
38+
39+
async checkNameExist(name) {
40+
const character = await this._db.collection('characters').findOne({ name });
41+
42+
if (character) {
43+
return true;
44+
} else {
45+
return false;
46+
}
47+
}
48+
49+
async getNextObjectId() {
50+
const objectId = await this._db.collection('counters').findOne(
51+
{
52+
"objectId": {
53+
$exists : true
54+
}
55+
},
56+
{
57+
projection: {
58+
_id: 0,
59+
"last": "$objectId.last",
60+
"start": "$objectId.start",
61+
}
62+
}
63+
);
64+
65+
await this._db.collection('counters').updateOne(
66+
{
67+
"objectId": {
68+
$exists : true
69+
}
70+
},
71+
{
72+
$inc: {
73+
"objectId.last": 1
74+
}
75+
}
76+
);
77+
78+
return objectId.start + objectId.last;
79+
}
80+
81+
async deleteCharacterByObjectId(objectId) {
82+
await this._db.collection('characters').deleteOne({ objectId });
83+
}
84+
}
85+
86+
module.exports = new Database();

GameServer/Client.js

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
const XOR = require('./libs/XOR.js');
2+
const xor = new XOR([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
3+
const clientPackets = require('./ClientPackets/clientPackets');
4+
5+
class Client {
6+
constructor(socket) {
7+
this._socket = socket;
8+
9+
this._init();
10+
}
11+
12+
sendPacket(packetInstance, encoding = true) {
13+
const buffer = packetInstance.getBuffer();
14+
const packetLength = this._getPacketLength(buffer);
15+
let payload = buffer;
16+
17+
// if (encoding) {
18+
// payload = Buffer.from(blowfish.encrypt(buffer));
19+
// }
20+
21+
const packet = Buffer.concat([packetLength, payload]);
22+
23+
this._socket.write(packet);
24+
}
25+
26+
_getPacketLength(buffer) {
27+
const length = Buffer.from([0x00, 0x00]);
28+
29+
length.writeInt16LE(buffer.length + 2);
30+
31+
return length;
32+
}
33+
34+
_onData(data) {
35+
const cropped = (Buffer.from(data, 'binary')).slice(2);
36+
const packet = Buffer.from(cropped);
37+
const opcode = packet[0];
38+
39+
console.log("opcode: ", opcode);
40+
41+
switch(opcode) {
42+
case 0:
43+
new clientPackets.ProtocolVersion(packet, this);
44+
45+
break;
46+
case 8:
47+
new clientPackets.RequestAuthLogin(packet, this);
48+
49+
break;
50+
case 13:
51+
new clientPackets.CharacterSelected(packet, this);
52+
53+
break;
54+
case 99:
55+
new clientPackets.RequestQuestList(packet, this);
56+
57+
break;
58+
case 3:
59+
new clientPackets.EnterWorld(packet, this);
60+
61+
break;
62+
case 14:
63+
new clientPackets.NewCharacter(packet, this);
64+
65+
break;
66+
case 11:
67+
new clientPackets.CharacterCreate(packet, this);
68+
69+
break;
70+
case 12:
71+
new clientPackets.CharacterDelete(packet, this);
72+
73+
break;
74+
case 1:
75+
new clientPackets.MoveBackwardToLocation(packet, this);
76+
77+
break;
78+
}
79+
}
80+
81+
_onClose() {
82+
console.log("client disconnect from login server");
83+
}
84+
85+
_init() {
86+
this._socket.setEncoding('binary');
87+
this._socket.on('error', () => {});
88+
this._socket.on('data', this._onData.bind(this));
89+
this._socket.on('close', this._onClose.bind(this));
90+
}
91+
}
92+
93+
module.exports = Client;
+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
const serverPackets = require('./../ServerPackets/serverPackets');
2+
const ClientPacket = require("./ClientPacket");
3+
const Character = require('./../Models/Character');
4+
const database = require('./../../Database');
5+
const characterTemplates = require('./../data/characterTemplates.json');
6+
const players = require('./../Models/Players');
7+
8+
class CharacterCreate {
9+
constructor(packet, client) {
10+
this._client = client;
11+
this._data = new ClientPacket(packet);
12+
this._data.readC()
13+
.readS()
14+
.readD()
15+
.readD()
16+
.readD()
17+
.readD()
18+
.readD()
19+
.readD()
20+
.readD()
21+
.readD()
22+
.readD()
23+
.readD()
24+
.readD()
25+
.readD();
26+
27+
this._init();
28+
}
29+
30+
get name() {
31+
return this._data.getData()[1];
32+
}
33+
34+
get race() {
35+
return this._data.getData()[2];
36+
}
37+
38+
get gender() {
39+
return this._data.getData()[3];
40+
}
41+
42+
get classId() {
43+
return this._data.getData()[4];
44+
}
45+
46+
get hairStyle() {
47+
return this._data.getData()[11];
48+
}
49+
50+
get hairColor() {
51+
return this._data.getData()[12];
52+
}
53+
54+
get face() {
55+
return this._data.getData()[13];
56+
}
57+
58+
_checkNameLetters(name) {
59+
const regexp = /^[0-9A-Za-z]*$/gi;
60+
61+
if (regexp.test(name)) {
62+
return true;
63+
} else {
64+
return false;
65+
}
66+
}
67+
68+
async checkMaxNumberCharacters(login) {
69+
const characters = await database.getCharactersByLogin(login);
70+
const MAXIMUM_NUMBER_OF_CHARACTERS = 7;
71+
72+
if (characters.length >= MAXIMUM_NUMBER_OF_CHARACTERS) {
73+
return true;
74+
} else {
75+
return false;
76+
}
77+
}
78+
79+
async _init() {
80+
const player = players.getPlayerByClient(this._client);
81+
82+
if (await this.checkMaxNumberCharacters(player.login)) {
83+
this._client.sendPacket(new serverPackets.CharacterCreateFail(serverPackets.CharacterCreateFail.reason.REASON_TOO_MANY_CHARACTERS))
84+
85+
return;
86+
}
87+
88+
const isUsedName = await database.checkNameExist(this.name);
89+
90+
if (isUsedName) {
91+
this._client.sendPacket(new serverPackets.CharacterCreateFail(serverPackets.CharacterCreateFail.reason.REASON_NAME_ALREADY_EXISTS))
92+
93+
return;
94+
}
95+
96+
if(this.name.length >= 16 || !this._checkNameLetters(this.name)) {
97+
this._client.sendPacket(new serverPackets.CharacterCreateFail(serverPackets.CharacterCreateFail.reason.REASON_16_ENG_CHARS))
98+
99+
return;
100+
}
101+
102+
const characterTemplate = characterTemplates.find(characterTemplate => {
103+
if (characterTemplate.classId === this.classId) {
104+
return true;
105+
} else {
106+
return false;
107+
}
108+
});
109+
const character = Character.create(characterTemplate);
110+
111+
character.name = this.name;
112+
character.objectId = await database.getNextObjectId();
113+
character.login = player.login;
114+
character.maximumHp = character.hp;
115+
character.maximumMp = character.mp;
116+
character.gender = this.gender;
117+
character.hairStyle = this.hairStyle;
118+
character.hairColor = this.hairColor;
119+
character.face = this.face;
120+
121+
//fix
122+
character.swimSpeed = 1;
123+
character.canCraft = 0;
124+
character.maleMovementMultiplier = null;
125+
character.maleAttackSpeedMultiplier = null;
126+
character.maleCollisionRadius = null;
127+
character.maleCollisionHeight = null;
128+
129+
character.femaleMovementMultiplier = null;
130+
character.femaleAttackSpeedMultiplier = null;
131+
character.femaleCollisionRadius = null;
132+
character.femaleCollisionHeight = null;
133+
134+
character.pAtk = 1;
135+
character.pSpd = 1;
136+
character.pDef = 1;
137+
character.evasion = 1;
138+
character.accuracy = 1;
139+
character.critical = 1;
140+
141+
character.mAtk = 1;
142+
character.mSpd = 1;
143+
character.pSpd = 1;
144+
character.mDef = 1;
145+
146+
character.items = null;
147+
//
148+
149+
await database.addCharacter(character);
150+
151+
const characters = await database.getCharactersByLogin(player.login);
152+
153+
this._client.sendPacket(new serverPackets.CharacterCreateSuccess());
154+
this._client.sendPacket(new serverPackets.CharacterSelectInfo(player.login, characters));
155+
}
156+
}
157+
158+
module.exports = CharacterCreate;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const serverPackets = require('./../ServerPackets/serverPackets');
2+
const ClientPacket = require("./ClientPacket");
3+
const database = require('./../../Database');
4+
const players = require('./../Models/Players');
5+
6+
class CharacterDelete {
7+
constructor(packet, client) {
8+
this._client = client;
9+
this._data = new ClientPacket(packet);
10+
this._data.readC()
11+
.readD();
12+
13+
this._init();
14+
}
15+
16+
get characterSlot () {
17+
return this._data.getData()[1];
18+
}
19+
20+
async _init() {
21+
const player = players.getPlayerByClient(this._client);
22+
const characters = await database.getCharactersByLogin(player.login);
23+
const character = characters[this.characterSlot];
24+
25+
await database.deleteCharacterByObjectId(character.objectId);
26+
27+
this._client.sendPacket(new serverPackets.CharacterDeleteOk());
28+
this._client.sendPacket(new serverPackets.CharacterSelectInfo(player.login, await database.getCharactersByLogin(player.login))); // fix?
29+
}
30+
}
31+
32+
module.exports = CharacterDelete;

0 commit comments

Comments
 (0)