mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2025-09-27 10:30:06 +00:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0078be8e9a | ||
b617456aa1
|
|||
935ee1bf6f
|
|||
43a2504357
|
|||
ca196bf620
|
|||
6b9ae4c325
|
|||
d06c324aa3
|
|||
052196d1cd
|
|||
e84f6505b8
|
|||
b483bf7190
|
|||
6ff51685a8
|
|||
b4ed31d4fb
|
|||
36e0667ed2 |
14
.github/workflows/check-builds.yaml
vendored
14
.github/workflows/check-builds.yaml
vendored
@@ -8,6 +8,7 @@ on:
|
|||||||
- .github/workflows/check-builds.yaml
|
- .github/workflows/check-builds.yaml
|
||||||
- CMakeLists.txt
|
- CMakeLists.txt
|
||||||
- Makefile
|
- Makefile
|
||||||
|
- tdata
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, reopened, synchronize, ready_for_review]
|
types: [opened, reopened, synchronize, ready_for_review]
|
||||||
paths:
|
paths:
|
||||||
@@ -19,7 +20,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu-build:
|
ubuntu-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Set environment
|
- name: Set environment
|
||||||
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||||
@@ -48,6 +49,7 @@ jobs:
|
|||||||
Rename-Item -Path "bin/fusion" -newName "$version-fusion"
|
Rename-Item -Path "bin/fusion" -newName "$version-fusion"
|
||||||
Write-Output "Built version $version"
|
Write-Output "Built version $version"
|
||||||
}
|
}
|
||||||
|
Copy-Item -Path "tdata" -Destination "bin/tdata" -Recurse
|
||||||
Copy-Item -Path "sql" -Destination "bin/sql" -Recurse
|
Copy-Item -Path "sql" -Destination "bin/sql" -Recurse
|
||||||
Copy-Item -Path "config.ini" -Destination "bin"
|
Copy-Item -Path "config.ini" -Destination "bin"
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
@@ -58,7 +60,7 @@ jobs:
|
|||||||
path: bin
|
path: bin
|
||||||
|
|
||||||
windows-build:
|
windows-build:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2022
|
||||||
steps:
|
steps:
|
||||||
- name: Set environment
|
- name: Set environment
|
||||||
run: $s = $env:GITHUB_SHA.subString(0, 7); echo "SHORT_SHA=$s" >> $env:GITHUB_ENV
|
run: $s = $env:GITHUB_SHA.subString(0, 7); echo "SHORT_SHA=$s" >> $env:GITHUB_ENV
|
||||||
@@ -73,7 +75,7 @@ jobs:
|
|||||||
$configurations = "Release"
|
$configurations = "Release"
|
||||||
# "Debug" builds are disabled, since we don't really need them
|
# "Debug" builds are disabled, since we don't really need them
|
||||||
|
|
||||||
$vsPath = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise"
|
$vsPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise"
|
||||||
|
|
||||||
Import-Module "$vsPath\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
|
Import-Module "$vsPath\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
|
||||||
Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation
|
Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation
|
||||||
@@ -100,6 +102,7 @@ jobs:
|
|||||||
}
|
}
|
||||||
Rename-Item -Path "bin/$configuration" -newName "$version-$configuration"
|
Rename-Item -Path "bin/$configuration" -newName "$version-$configuration"
|
||||||
Write-Output "Built version $version $configuration"
|
Write-Output "Built version $version $configuration"
|
||||||
|
Copy-Item -Path "tdata" -Destination "bin/$version-$configuration/tdata" -Recurse
|
||||||
Copy-Item -Path "sql" -Destination "bin/$version-$configuration/sql" -Recurse
|
Copy-Item -Path "sql" -Destination "bin/$version-$configuration/sql" -Recurse
|
||||||
Copy-Item -Path "config.ini" -Destination "bin/$version-$configuration"
|
Copy-Item -Path "config.ini" -Destination "bin/$version-$configuration"
|
||||||
}
|
}
|
||||||
@@ -108,11 +111,11 @@ jobs:
|
|||||||
- name: Upload build artifact
|
- name: Upload build artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: 'windows-vs2019-bin-x64-${{ env.SHORT_SHA }}'
|
name: 'windows-vs2022-bin-x64-${{ env.SHORT_SHA }}'
|
||||||
path: bin
|
path: bin
|
||||||
|
|
||||||
copy-artifacts:
|
copy-artifacts:
|
||||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master'
|
if: github.event_name != 'pull_request' && (github.ref_type == 'tag' || github.ref_name == 'master')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [windows-build, ubuntu-build]
|
needs: [windows-build, ubuntu-build]
|
||||||
env:
|
env:
|
||||||
@@ -121,7 +124,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: |
|
- run: |
|
||||||
GITDESC=$(git describe --tags)
|
GITDESC=$(git describe --tags)
|
||||||
|
@@ -38,4 +38,4 @@ EXPOSE 23000/tcp
|
|||||||
EXPOSE 23001/tcp
|
EXPOSE 23001/tcp
|
||||||
EXPOSE 8003/tcp
|
EXPOSE 8003/tcp
|
||||||
|
|
||||||
LABEL Name=openfusion Version=1.6.0
|
LABEL Name=openfusion Version=2.0.0
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2020-2024 OpenFusion Contributors
|
Copyright (c) 2020-2025 OpenFusion Contributors
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
10
README.md
10
README.md
@@ -14,22 +14,22 @@ OpenFusion is a reverse-engineered server for FusionFall. It primarily targets v
|
|||||||
|
|
||||||
### Getting Started
|
### Getting Started
|
||||||
#### Method A: Installer (Easiest)
|
#### Method A: Installer (Easiest)
|
||||||
1. Download the client installer by clicking [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.6/OpenFusionClient-1.6-Installer.exe) - choose to run the file.
|
1. Download the launcher installer by clicking [here](https://github.com/OpenFusionProject/OpenFusionLauncher/releases/latest/download/OpenFusionLauncher-Windows-Installer.exe) - choose to run the file.
|
||||||
2. After a few moments, the client should open: you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
2. After a few moments, the launcher should open: you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
||||||
3. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
3. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
||||||
4. Make a new character, and enjoy the game! Your progress will be saved automatically, and you can resume playing by entering the login details you used in step 3.
|
4. Make a new character, and enjoy the game! Your progress will be saved automatically, and you can resume playing by entering the login details you used in step 3.
|
||||||
|
|
||||||
#### Method B: Standalone .zip file
|
#### Method B: Standalone .zip file
|
||||||
1. Download the client from [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.6/OpenFusionClient-1.6.zip).
|
1. Download the launcher from [here](https://github.com/OpenFusionProject/OpenFusionLauncher/releases/latest/download/OpenFusionLauncher-Windows-Portable.zip).
|
||||||
2. Extract it to a folder of your choice. Note: if you are upgrading from an older version, it is preferable to start with a fresh folder rather than overwriting a previous install.
|
2. Extract it to a folder of your choice. Note: if you are upgrading from an older version, it is preferable to start with a fresh folder rather than overwriting a previous install.
|
||||||
3. Run OpenFusionClient.exe - you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
3. Run OpenFusionLauncher.exe - you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
||||||
4. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
4. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
||||||
5. Make a new character, and enjoy the game! Your progress will be saved automatically, and you can resume playing by entering the login details you used in step 4.
|
5. Make a new character, and enjoy the game! Your progress will be saved automatically, and you can resume playing by entering the login details you used in step 4.
|
||||||
|
|
||||||
Instructions for getting the client to run on Linux through Wine can be found [here](https://openfusion.dev/docs/guides/running-on-linux/).
|
Instructions for getting the client to run on Linux through Wine can be found [here](https://openfusion.dev/docs/guides/running-on-linux/).
|
||||||
|
|
||||||
### Hosting a server
|
### Hosting a server
|
||||||
1. Grab `OpenFusionServer-1.6-Original.zip` or `OpenFusionServer-1.6-Academy.zip` from [here](https://github.com/OpenFusionProject/OpenFusion/releases/tag/1.6).
|
1. Grab `OpenFusionServer-Windows-Original.zip` or `OpenFusionServer-Windows-Academy.zip` from [here](https://github.com/OpenFusionProject/OpenFusion/releases/latest).
|
||||||
2. Extract it to a folder of your choice, then run `winfusion.exe` (Windows) or `fusion` (Linux) to start the server.
|
2. Extract it to a folder of your choice, then run `winfusion.exe` (Windows) or `fusion` (Linux) to start the server.
|
||||||
3. Add a new server to the client's list:
|
3. Add a new server to the client's list:
|
||||||
1. For Description, enter anything you want. This is what will show up in the server list.
|
1. For Description, enter anything you want. This is what will show up in the server list.
|
||||||
|
@@ -12,6 +12,8 @@ sandbox=true
|
|||||||
[login]
|
[login]
|
||||||
# must be kept in sync with loginInfo.php
|
# must be kept in sync with loginInfo.php
|
||||||
port=23000
|
port=23000
|
||||||
|
# will all name wheel names be approved instantly?
|
||||||
|
acceptallwheelnames=true
|
||||||
# will all custom names be approved instantly?
|
# will all custom names be approved instantly?
|
||||||
acceptallcustomnames=true
|
acceptallcustomnames=true
|
||||||
# should attempts to log into non-existent accounts
|
# should attempts to log into non-existent accounts
|
||||||
|
8
sql/migration5.sql
Normal file
8
sql/migration5.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
BEGIN TRANSACTION;
|
||||||
|
-- New Columns
|
||||||
|
ALTER TABLE Accounts ADD Email TEXT DEFAULT '' NOT NULL;
|
||||||
|
ALTER TABLE Accounts ADD LastPasswordReset INTEGER DEFAULT 0 NOT NULL;
|
||||||
|
-- Update DB Version
|
||||||
|
UPDATE Meta SET Value = 6 WHERE Key = 'DatabaseVersion';
|
||||||
|
UPDATE Meta SET Value = strftime('%s', 'now') WHERE Key = 'LastMigration';
|
||||||
|
COMMIT;
|
@@ -1,14 +1,16 @@
|
|||||||
CREATE TABLE IF NOT EXISTS Accounts (
|
CREATE TABLE IF NOT EXISTS Accounts (
|
||||||
AccountID INTEGER NOT NULL,
|
AccountID INTEGER NOT NULL,
|
||||||
Login TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
Login TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
||||||
Password TEXT NOT NULL,
|
Password TEXT NOT NULL,
|
||||||
Selected INTEGER DEFAULT 1 NOT NULL,
|
Selected INTEGER DEFAULT 1 NOT NULL,
|
||||||
AccountLevel INTEGER NOT NULL,
|
AccountLevel INTEGER NOT NULL,
|
||||||
Created INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
|
Created INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
|
||||||
LastLogin INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
|
LastLogin INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
|
||||||
BannedUntil INTEGER DEFAULT 0 NOT NULL,
|
BannedUntil INTEGER DEFAULT 0 NOT NULL,
|
||||||
BannedSince INTEGER DEFAULT 0 NOT NULL,
|
BannedSince INTEGER DEFAULT 0 NOT NULL,
|
||||||
BanReason TEXT DEFAULT '' NOT NULL,
|
BanReason TEXT DEFAULT '' NOT NULL,
|
||||||
|
Email TEXT DEFAULT '' NOT NULL,
|
||||||
|
LastPasswordReset INTEGER DEFAULT 0 NOT NULL,
|
||||||
PRIMARY KEY(AccountID AUTOINCREMENT)
|
PRIMARY KEY(AccountID AUTOINCREMENT)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
32
src/Chat.cpp
32
src/Chat.cpp
@@ -1,6 +1,7 @@
|
|||||||
#include "Chat.hpp"
|
#include "Chat.hpp"
|
||||||
|
|
||||||
#include "servers/CNShardServer.hpp"
|
#include "servers/CNShardServer.hpp"
|
||||||
|
#include "servers/Monitor.hpp"
|
||||||
|
|
||||||
#include "Player.hpp"
|
#include "Player.hpp"
|
||||||
#include "PlayerManager.hpp"
|
#include "PlayerManager.hpp"
|
||||||
@@ -8,8 +9,6 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
std::vector<std::string> Chat::dump;
|
|
||||||
|
|
||||||
using namespace Chat;
|
using namespace Chat;
|
||||||
|
|
||||||
static void chatHandler(CNSocket* sock, CNPacketData* data) {
|
static void chatHandler(CNSocket* sock, CNPacketData* data) {
|
||||||
@@ -28,7 +27,7 @@ static void chatHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
std::string logLine = "[FreeChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
std::string logLine = "[FreeChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
||||||
|
|
||||||
std::cout << logLine << std::endl;
|
std::cout << logLine << std::endl;
|
||||||
dump.push_back(logLine);
|
Monitor::chats.push_back(logLine);
|
||||||
|
|
||||||
// send to client
|
// send to client
|
||||||
INITSTRUCT(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, resp);
|
||||||
@@ -51,7 +50,7 @@ static void menuChatHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
std::string logLine = "[MenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
std::string logLine = "[MenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
||||||
|
|
||||||
std::cout << logLine << std::endl;
|
std::cout << logLine << std::endl;
|
||||||
dump.push_back(logLine);
|
Monitor::chats.push_back(logLine);
|
||||||
|
|
||||||
// send to client
|
// send to client
|
||||||
INITSTRUCT(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, resp);
|
||||||
@@ -103,14 +102,14 @@ static void announcementHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
memcpy(msg.szAnnounceMsg, announcement->szAnnounceMsg, sizeof(msg.szAnnounceMsg));
|
memcpy(msg.szAnnounceMsg, announcement->szAnnounceMsg, sizeof(msg.szAnnounceMsg));
|
||||||
std::map<CNSocket*, Player*>::iterator it;
|
std::map<CNSocket*, Player*>::iterator it;
|
||||||
|
|
||||||
|
// This value is completely arbitrary, but these make the most sense when you consider the architecture of the game
|
||||||
switch (announcement->iAreaType) {
|
switch (announcement->iAreaType) {
|
||||||
case 0: // area (all players in viewable chunks)
|
case 0: // area (all players in viewable chunks)
|
||||||
sock->sendPacket(msg, P_FE2CL_GM_REP_PC_ANNOUNCE);
|
sock->sendPacket(msg, P_FE2CL_GM_REP_PC_ANNOUNCE);
|
||||||
PlayerManager::sendToViewable(sock, msg, P_FE2CL_GM_REP_PC_ANNOUNCE);
|
PlayerManager::sendToViewable(sock, msg, P_FE2CL_GM_REP_PC_ANNOUNCE);
|
||||||
break;
|
break;
|
||||||
case 1: // shard
|
case 1: // channel
|
||||||
case 2: // world
|
case 2: // shard
|
||||||
break; // not applicable to OpenFusion
|
|
||||||
case 3: // global (all players)
|
case 3: // global (all players)
|
||||||
for (it = PlayerManager::players.begin(); it != PlayerManager::players.end(); it++) {
|
for (it = PlayerManager::players.begin(); it != PlayerManager::players.end(); it++) {
|
||||||
CNSocket* allSock = it->first;
|
CNSocket* allSock = it->first;
|
||||||
@@ -120,9 +119,12 @@ static void announcementHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string logLine = "[Bcast " + std::to_string(announcement->iAreaType) + "] " + PlayerManager::getPlayerName(plr, false) + ": " + AUTOU16TOU8(msg.szAnnounceMsg);
|
std::string logLine = std::to_string(announcement->iAreaType) + " "
|
||||||
std::cout << logLine << std::endl;
|
+ std::to_string(announcement->iAnnounceType) + " "
|
||||||
dump.push_back("**" + logLine + "**");
|
+ std::to_string(announcement->iDuringTime) + " "
|
||||||
|
+ PlayerManager::getPlayerName(plr, false) + ": " + AUTOU16TOU8(msg.szAnnounceMsg);
|
||||||
|
std::cout << "Broadcast " << logLine << std::endl;
|
||||||
|
Monitor::bcasts.push_back(logLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buddy freechatting
|
// Buddy freechatting
|
||||||
@@ -155,7 +157,7 @@ static void buddyChatHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
std::string logLine = "[BuddyChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
std::string logLine = "[BuddyChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
||||||
std::cout << logLine << std::endl;
|
std::cout << logLine << std::endl;
|
||||||
dump.push_back(logLine);
|
Monitor::chats.push_back(logLine);
|
||||||
|
|
||||||
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
|
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
|
||||||
|
|
||||||
@@ -185,7 +187,7 @@ static void buddyMenuChatHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
std::string logLine = "[BuddyMenuChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
std::string logLine = "[BuddyMenuChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
||||||
|
|
||||||
std::cout << logLine << std::endl;
|
std::cout << logLine << std::endl;
|
||||||
dump.push_back(logLine);
|
Monitor::chats.push_back(logLine);
|
||||||
|
|
||||||
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
|
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
|
||||||
|
|
||||||
@@ -218,7 +220,7 @@ static void tradeChatHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
std::string logLine = "[TradeChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
std::string logLine = "[TradeChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
||||||
|
|
||||||
std::cout << logLine << std::endl;
|
std::cout << logLine << std::endl;
|
||||||
dump.push_back(logLine);
|
Monitor::chats.push_back(logLine);
|
||||||
|
|
||||||
resp.iEmoteCode = pacdat->iEmoteCode;
|
resp.iEmoteCode = pacdat->iEmoteCode;
|
||||||
sock->sendPacket(resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT);
|
sock->sendPacket(resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT);
|
||||||
@@ -241,7 +243,7 @@ static void groupChatHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
std::string logLine = "[GroupChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
std::string logLine = "[GroupChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
||||||
std::cout << logLine << std::endl;
|
std::cout << logLine << std::endl;
|
||||||
dump.push_back(logLine);
|
Monitor::chats.push_back(logLine);
|
||||||
|
|
||||||
// send to client
|
// send to client
|
||||||
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, resp);
|
||||||
@@ -264,7 +266,7 @@ static void groupMenuChatHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
std::string logLine = "[GroupMenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
std::string logLine = "[GroupMenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
||||||
|
|
||||||
std::cout << logLine << std::endl;
|
std::cout << logLine << std::endl;
|
||||||
dump.push_back(logLine);
|
Monitor::chats.push_back(logLine);
|
||||||
|
|
||||||
// send to client
|
// send to client
|
||||||
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, resp);
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Chat {
|
namespace Chat {
|
||||||
extern std::vector<std::string> dump;
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void sendServerMessage(CNSocket* sock, std::string msg); // uses MOTD
|
void sendServerMessage(CNSocket* sock, std::string msg); // uses MOTD
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
#include "core/Core.hpp"
|
#include "core/Core.hpp"
|
||||||
#include "db/Database.hpp"
|
#include "db/Database.hpp"
|
||||||
#include "servers/CNShardServer.hpp"
|
#include "servers/CNShardServer.hpp"
|
||||||
|
#include "servers/Monitor.hpp"
|
||||||
|
|
||||||
#include "PlayerManager.hpp"
|
#include "PlayerManager.hpp"
|
||||||
#include "Items.hpp"
|
#include "Items.hpp"
|
||||||
@@ -10,8 +11,6 @@
|
|||||||
|
|
||||||
using namespace Email;
|
using namespace Email;
|
||||||
|
|
||||||
std::vector<std::string> Email::dump;
|
|
||||||
|
|
||||||
// New email notification
|
// New email notification
|
||||||
static void emailUpdateCheck(CNSocket* sock, CNPacketData* data) {
|
static void emailUpdateCheck(CNSocket* sock, CNPacketData* data) {
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_NEW_EMAIL, resp);
|
INITSTRUCT(sP_FE2CL_REP_PC_NEW_EMAIL, resp);
|
||||||
@@ -324,7 +323,7 @@ static void emailSend(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
std::string logEmail = "[Email] " + PlayerManager::getPlayerName(plr, true) + " (to " + PlayerManager::getPlayerName(&otherPlr, true) + "): <" + email.SubjectLine + ">\n" + email.MsgBody;
|
std::string logEmail = "[Email] " + PlayerManager::getPlayerName(plr, true) + " (to " + PlayerManager::getPlayerName(&otherPlr, true) + "): <" + email.SubjectLine + ">\n" + email.MsgBody;
|
||||||
std::cout << logEmail << std::endl;
|
std::cout << logEmail << std::endl;
|
||||||
dump.push_back(logEmail);
|
Monitor::emails.push_back(logEmail);
|
||||||
|
|
||||||
// notification to recipient if online
|
// notification to recipient if online
|
||||||
CNSocket* recipient = PlayerManager::getSockFromID(pkt->iTo_PCUID);
|
CNSocket* recipient = PlayerManager::getSockFromID(pkt->iTo_PCUID);
|
||||||
|
@@ -4,7 +4,5 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace Email {
|
namespace Email {
|
||||||
extern std::vector<std::string> dump;
|
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
}
|
}
|
||||||
|
@@ -620,6 +620,10 @@ std::string PlayerManager::getPlayerName(Player *plr, bool id) {
|
|||||||
if (plr == nullptr)
|
if (plr == nullptr)
|
||||||
return "NOT IN GAME";
|
return "NOT IN GAME";
|
||||||
|
|
||||||
|
if (plr->PCStyle.iNameCheck != 1) {
|
||||||
|
return "Player " + std::to_string(plr->iID);
|
||||||
|
}
|
||||||
|
|
||||||
std::string ret = "";
|
std::string ret = "";
|
||||||
if (id && plr->accountLevel <= 30)
|
if (id && plr->accountLevel <= 30)
|
||||||
ret += "(GM) ";
|
ret += "(GM) ";
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
#include "TableData.hpp"
|
#include "TableData.hpp"
|
||||||
|
|
||||||
|
#include "servers/CNLoginServer.hpp"
|
||||||
|
|
||||||
#include "NPCManager.hpp"
|
#include "NPCManager.hpp"
|
||||||
#include "Missions.hpp"
|
#include "Missions.hpp"
|
||||||
#include "Items.hpp"
|
#include "Items.hpp"
|
||||||
@@ -79,6 +81,25 @@ static void loadXDT(json& xdtData) {
|
|||||||
NPCManager::NPCData = xdtData["m_pNpcTable"]["m_pNpcData"];
|
NPCManager::NPCData = xdtData["m_pNpcTable"]["m_pNpcData"];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// load name wheel names
|
||||||
|
json firstNameData = xdtData["m_pNameTable"]["m_pFirstName"];
|
||||||
|
for (json::iterator _name = firstNameData.begin(); _name != firstNameData.end(); _name++) {
|
||||||
|
auto name = _name.value();
|
||||||
|
LoginServer::WheelFirstNames.push_back(name["m_pstrNameString"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
json middleNameData = xdtData["m_pNameTable"]["m_pMiddleName"];
|
||||||
|
for (json::iterator _name = middleNameData.begin(); _name != middleNameData.end(); _name++) {
|
||||||
|
auto name = _name.value();
|
||||||
|
LoginServer::WheelMiddleNames.push_back(name["m_pstrNameString"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
json lastNameData = xdtData["m_pNameTable"]["m_pLastName"];
|
||||||
|
for (json::iterator _name = lastNameData.begin(); _name != lastNameData.end(); _name++) {
|
||||||
|
auto name = _name.value();
|
||||||
|
LoginServer::WheelLastNames.push_back(name["m_pstrNameString"]);
|
||||||
|
}
|
||||||
|
|
||||||
// load warps
|
// load warps
|
||||||
json warpData = xdtData["m_pInstanceTable"]["m_pWarpData"];
|
json warpData = xdtData["m_pInstanceTable"]["m_pWarpData"];
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define DATABASE_VERSION 5
|
#define DATABASE_VERSION 6
|
||||||
|
|
||||||
namespace Database {
|
namespace Database {
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ namespace Database {
|
|||||||
bool isNameFree(std::string firstName, std::string lastName);
|
bool isNameFree(std::string firstName, std::string lastName);
|
||||||
bool isSlotFree(int accountId, int slotNum);
|
bool isSlotFree(int accountId, int slotNum);
|
||||||
/// returns ID, 0 if something failed
|
/// returns ID, 0 if something failed
|
||||||
int createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID);
|
int createCharacter(int slot, int accountId, const char* firstName, const char* lastName, int nameCheck);
|
||||||
/// returns true if query succeeded
|
/// returns true if query succeeded
|
||||||
bool finishCharacter(sP_CL2LS_REQ_CHAR_CREATE* character, int accountId);
|
bool finishCharacter(sP_CL2LS_REQ_CHAR_CREATE* character, int accountId);
|
||||||
/// returns true if query succeeded
|
/// returns true if query succeeded
|
||||||
@@ -85,7 +85,7 @@ namespace Database {
|
|||||||
};
|
};
|
||||||
void evaluateCustomName(int characterID, CustomName decision);
|
void evaluateCustomName(int characterID, CustomName decision);
|
||||||
/// returns true if query succeeded
|
/// returns true if query succeeded
|
||||||
bool changeName(sP_CL2LS_REQ_CHANGE_CHAR_NAME* save, int accountId);
|
bool changeName(int playerId, int accountId, const char* firstName, const char* lastName, int nameCheck);
|
||||||
|
|
||||||
// getting players
|
// getting players
|
||||||
void getPlayer(Player* plr, int id);
|
void getPlayer(Player* plr, int id);
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "db/internal.hpp"
|
#include "db/internal.hpp"
|
||||||
|
|
||||||
|
#include "servers/CNLoginServer.hpp"
|
||||||
|
|
||||||
#include "bcrypt/BCrypt.hpp"
|
#include "bcrypt/BCrypt.hpp"
|
||||||
|
|
||||||
void Database::findAccount(Account* account, std::string login) {
|
void Database::findAccount(Account* account, std::string login) {
|
||||||
@@ -291,7 +293,7 @@ bool Database::isSlotFree(int accountId, int slotNum) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Database::createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID) {
|
int Database::createCharacter(int slot, int accountId, const char* firstName, const char* lastName, int nameCheck) {
|
||||||
std::lock_guard<std::mutex> lock(dbCrit);
|
std::lock_guard<std::mutex> lock(dbCrit);
|
||||||
|
|
||||||
sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||||||
@@ -304,22 +306,17 @@ int Database::createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID)
|
|||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
)";
|
)";
|
||||||
sqlite3_stmt* stmt;
|
sqlite3_stmt* stmt;
|
||||||
std::string firstName = AUTOU16TOU8(save->szFirstName);
|
|
||||||
std::string lastName = AUTOU16TOU8(save->szLastName);
|
|
||||||
|
|
||||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||||
sqlite3_bind_int(stmt, 1, AccountID);
|
sqlite3_bind_int(stmt, 1, accountId);
|
||||||
sqlite3_bind_int(stmt, 2, save->iSlotNum);
|
sqlite3_bind_int(stmt, 2, slot);
|
||||||
sqlite3_bind_text(stmt, 3, firstName.c_str(), -1, NULL);
|
sqlite3_bind_text(stmt, 3, firstName, -1, NULL);
|
||||||
sqlite3_bind_text(stmt, 4, lastName.c_str(), -1, NULL);
|
sqlite3_bind_text(stmt, 4, lastName, -1, NULL);
|
||||||
sqlite3_bind_int(stmt, 5, settings::SPAWN_X);
|
sqlite3_bind_int(stmt, 5, settings::SPAWN_X);
|
||||||
sqlite3_bind_int(stmt, 6, settings::SPAWN_Y);
|
sqlite3_bind_int(stmt, 6, settings::SPAWN_Y);
|
||||||
sqlite3_bind_int(stmt, 7, settings::SPAWN_Z);
|
sqlite3_bind_int(stmt, 7, settings::SPAWN_Z);
|
||||||
sqlite3_bind_int(stmt, 8, settings::SPAWN_ANGLE);
|
sqlite3_bind_int(stmt, 8, settings::SPAWN_ANGLE);
|
||||||
sqlite3_bind_int(stmt, 9, PC_MAXHEALTH(1));
|
sqlite3_bind_int(stmt, 9, PC_MAXHEALTH(1));
|
||||||
|
|
||||||
// if FNCode isn't 0, it's a wheel name
|
|
||||||
int nameCheck = (settings::APPROVEALLNAMES || save->iFNCode) ? 1 : 0;
|
|
||||||
sqlite3_bind_int(stmt, 10, nameCheck);
|
sqlite3_bind_int(stmt, 10, nameCheck);
|
||||||
|
|
||||||
// blobs
|
// blobs
|
||||||
@@ -648,7 +645,7 @@ void Database::evaluateCustomName(int characterID, CustomName decision) {
|
|||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Database::changeName(sP_CL2LS_REQ_CHANGE_CHAR_NAME* save, int accountId) {
|
bool Database::changeName(int playerId, int accountId, const char* firstName, const char* lastName, int nameCheck) {
|
||||||
std::lock_guard<std::mutex> lock(dbCrit);
|
std::lock_guard<std::mutex> lock(dbCrit);
|
||||||
|
|
||||||
const char* sql = R"(
|
const char* sql = R"(
|
||||||
@@ -662,15 +659,10 @@ bool Database::changeName(sP_CL2LS_REQ_CHANGE_CHAR_NAME* save, int accountId) {
|
|||||||
sqlite3_stmt* stmt;
|
sqlite3_stmt* stmt;
|
||||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||||
|
|
||||||
std::string firstName = AUTOU16TOU8(save->szFirstName);
|
sqlite3_bind_text(stmt, 1, firstName, -1, NULL);
|
||||||
std::string lastName = AUTOU16TOU8(save->szLastName);
|
sqlite3_bind_text(stmt, 2, lastName, -1, NULL);
|
||||||
|
|
||||||
sqlite3_bind_text(stmt, 1, firstName.c_str(), -1, NULL);
|
|
||||||
sqlite3_bind_text(stmt, 2, lastName.c_str(), -1, NULL);
|
|
||||||
// if FNCode isn't 0, it's a wheel name
|
|
||||||
int nameCheck = (settings::APPROVEALLNAMES || save->iFNCode) ? 1 : 0;
|
|
||||||
sqlite3_bind_int(stmt, 3, nameCheck);
|
sqlite3_bind_int(stmt, 3, nameCheck);
|
||||||
sqlite3_bind_int(stmt, 4, save->iPCUID);
|
sqlite3_bind_int(stmt, 4, playerId);
|
||||||
sqlite3_bind_int(stmt, 5, accountId);
|
sqlite3_bind_int(stmt, 5, accountId);
|
||||||
|
|
||||||
int rc = sqlite3_step(stmt);
|
int rc = sqlite3_step(stmt);
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
#include "servers/CNLoginServer.hpp"
|
#include "servers/CNLoginServer.hpp"
|
||||||
|
#include "servers/Monitor.hpp"
|
||||||
|
|
||||||
#include "core/CNShared.hpp"
|
#include "core/CNShared.hpp"
|
||||||
#include "db/Database.hpp"
|
#include "db/Database.hpp"
|
||||||
@@ -12,6 +13,12 @@
|
|||||||
|
|
||||||
std::map<CNSocket*, CNLoginData> CNLoginServer::loginSessions;
|
std::map<CNSocket*, CNLoginData> CNLoginServer::loginSessions;
|
||||||
|
|
||||||
|
namespace LoginServer {
|
||||||
|
std::vector<std::string> WheelFirstNames;
|
||||||
|
std::vector<std::string> WheelMiddleNames;
|
||||||
|
std::vector<std::string> WheelLastNames;
|
||||||
|
}
|
||||||
|
|
||||||
CNLoginServer::CNLoginServer(uint16_t p) {
|
CNLoginServer::CNLoginServer(uint16_t p) {
|
||||||
serverType = "login";
|
serverType = "login";
|
||||||
port = p;
|
port = p;
|
||||||
@@ -285,10 +292,29 @@ void CNLoginServer::nameSave(CNSocket* sock, CNPacketData* data) {
|
|||||||
INITSTRUCT(sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC, resp);
|
INITSTRUCT(sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC, resp);
|
||||||
|
|
||||||
int errorCode = 0;
|
int errorCode = 0;
|
||||||
if (!CNLoginServer::isCharacterNameGood(AUTOU16TOU8(save->szFirstName), AUTOU16TOU8(save->szLastName))) {
|
|
||||||
errorCode = 4;
|
std::string firstName = AUTOU16TOU8(save->szFirstName);
|
||||||
} else if (!Database::isNameFree(AUTOU16TOU8(save->szFirstName), AUTOU16TOU8(save->szLastName))) {
|
std::string lastName = AUTOU16TOU8(save->szLastName);
|
||||||
errorCode = 1;
|
int nameCheck = 0;
|
||||||
|
|
||||||
|
// if FNCode isn't 0, it's a wheel name
|
||||||
|
if (save->iFNCode != 0) {
|
||||||
|
if (!CNLoginServer::isNameWheelNameGood(save->iFNCode, save->iMNCode, save->iLNCode, firstName, lastName)) {
|
||||||
|
errorCode = 4;
|
||||||
|
} else {
|
||||||
|
nameCheck = settings:: APPROVEWHEELNAMES ? 1 : 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// custom name
|
||||||
|
nameCheck = settings::APPROVECUSTOMNAMES ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorCode == 0) {
|
||||||
|
if (!CNLoginServer::isCharacterNameGood(firstName, lastName)) {
|
||||||
|
errorCode = 4;
|
||||||
|
} else if (!Database::isNameFree(firstName, lastName)) {
|
||||||
|
errorCode = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorCode != 0) {
|
if (errorCode != 0) {
|
||||||
@@ -306,12 +332,19 @@ void CNLoginServer::nameSave(CNSocket* sock, CNPacketData* data) {
|
|||||||
if (!Database::isSlotFree(loginSessions[sock].userID, save->iSlotNum))
|
if (!Database::isSlotFree(loginSessions[sock].userID, save->iSlotNum))
|
||||||
return invalidCharacter(sock);
|
return invalidCharacter(sock);
|
||||||
|
|
||||||
resp.iPC_UID = Database::createCharacter(save, loginSessions[sock].userID);
|
resp.iPC_UID = Database::createCharacter(save->iSlotNum, loginSessions[sock].userID, firstName.c_str(), lastName.c_str(), nameCheck);
|
||||||
// if query somehow failed
|
// if query somehow failed
|
||||||
if (resp.iPC_UID == 0) {
|
if (resp.iPC_UID == 0) {
|
||||||
std::cout << "[WARN] Login Server: Database failed to create new character!" << std::endl;
|
std::cout << "[WARN] Login Server: Database failed to create new character!" << std::endl;
|
||||||
return invalidCharacter(sock);
|
return invalidCharacter(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fire name check event if needed
|
||||||
|
if (nameCheck != 1) {
|
||||||
|
std::string namereq = std::to_string(resp.iPC_UID) + " " + firstName + " " + lastName;
|
||||||
|
Monitor::namereqs.push_back(namereq);
|
||||||
|
}
|
||||||
|
|
||||||
resp.iSlotNum = save->iSlotNum;
|
resp.iSlotNum = save->iSlotNum;
|
||||||
resp.iGender = save->iGender;
|
resp.iGender = save->iGender;
|
||||||
|
|
||||||
@@ -327,7 +360,9 @@ void CNLoginServer::nameSave(CNSocket* sock, CNPacketData* data) {
|
|||||||
DEBUGLOG(
|
DEBUGLOG(
|
||||||
std::cout << "Login Server: new character created" << std::endl;
|
std::cout << "Login Server: new character created" << std::endl;
|
||||||
std::cout << "\tSlot: " << (int)save->iSlotNum << std::endl;
|
std::cout << "\tSlot: " << (int)save->iSlotNum << std::endl;
|
||||||
std::cout << "\tName: " << AUTOU16TOU8(save->szFirstName) << " " << AUTOU16TOU8(save->szLastName) << std::endl;
|
std::cout << "\tName: " << firstName << " " << lastName;
|
||||||
|
if (nameCheck != 1) std::cout << " (pending approval)";
|
||||||
|
std::cout << std::endl;
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,11 +529,30 @@ void CNLoginServer::changeName(CNSocket* sock, CNPacketData* data) {
|
|||||||
auto save = (sP_CL2LS_REQ_CHANGE_CHAR_NAME*)data->buf;
|
auto save = (sP_CL2LS_REQ_CHANGE_CHAR_NAME*)data->buf;
|
||||||
|
|
||||||
int errorCode = 0;
|
int errorCode = 0;
|
||||||
if (!CNLoginServer::isCharacterNameGood(AUTOU16TOU8(save->szFirstName), AUTOU16TOU8(save->szLastName))) {
|
|
||||||
errorCode = 4;
|
std::string firstName = AUTOU16TOU8(save->szFirstName);
|
||||||
|
std::string lastName = AUTOU16TOU8(save->szLastName);
|
||||||
|
int nameCheck = 0;
|
||||||
|
|
||||||
|
// if FNCode isn't 0, it's a wheel name
|
||||||
|
if (save->iFNCode != 0) {
|
||||||
|
if (!CNLoginServer::isNameWheelNameGood(save->iFNCode, save->iMNCode, save->iLNCode, firstName, lastName)) {
|
||||||
|
errorCode = 4;
|
||||||
|
} else {
|
||||||
|
nameCheck = settings::APPROVEWHEELNAMES ? 1 : 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// custom name
|
||||||
|
nameCheck = settings::APPROVECUSTOMNAMES ? 1 : 0;
|
||||||
}
|
}
|
||||||
else if (!Database::isNameFree(AUTOU16TOU8(save->szFirstName), AUTOU16TOU8(save->szLastName))) {
|
|
||||||
errorCode = 1;
|
if (errorCode == 0) {
|
||||||
|
if (!CNLoginServer::isCharacterNameGood(firstName, lastName)) {
|
||||||
|
errorCode = 4;
|
||||||
|
}
|
||||||
|
else if (!Database::isNameFree(firstName, lastName)) {
|
||||||
|
errorCode = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorCode != 0) {
|
if (errorCode != 0) {
|
||||||
@@ -513,9 +567,15 @@ void CNLoginServer::changeName(CNSocket* sock, CNPacketData* data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Database::changeName(save, loginSessions[sock].userID))
|
if (!Database::changeName(save->iPCUID, loginSessions[sock].userID, firstName.c_str(), lastName.c_str(), nameCheck))
|
||||||
return invalidCharacter(sock);
|
return invalidCharacter(sock);
|
||||||
|
|
||||||
|
// fire name check event if needed
|
||||||
|
if (nameCheck != 1) {
|
||||||
|
std::string namereq = std::to_string(save->iPCUID) + " " + firstName + " " + lastName;
|
||||||
|
Monitor::namereqs.push_back(namereq);
|
||||||
|
}
|
||||||
|
|
||||||
INITSTRUCT(sP_LS2CL_REP_CHANGE_CHAR_NAME_SUCC, resp);
|
INITSTRUCT(sP_LS2CL_REP_CHANGE_CHAR_NAME_SUCC, resp);
|
||||||
resp.iPC_UID = save->iPCUID;
|
resp.iPC_UID = save->iPCUID;
|
||||||
memcpy(resp.szFirstName, save->szFirstName, sizeof(resp.szFirstName));
|
memcpy(resp.szFirstName, save->szFirstName, sizeof(resp.szFirstName));
|
||||||
@@ -527,8 +587,10 @@ void CNLoginServer::changeName(CNSocket* sock, CNPacketData* data) {
|
|||||||
sock->sendPacket(resp, P_LS2CL_REP_CHANGE_CHAR_NAME_SUCC);
|
sock->sendPacket(resp, P_LS2CL_REP_CHANGE_CHAR_NAME_SUCC);
|
||||||
|
|
||||||
DEBUGLOG(
|
DEBUGLOG(
|
||||||
std::cout << "Login Server: Name check success for character [" << save->iPCUID << "]" << std::endl;
|
std::cout << "Login Server: Name change request for character [" << save->iPCUID << "]" << std::endl;
|
||||||
std::cout << "\tNew name: " << AUTOU16TOU8(save->szFirstName) << " " << AUTOU16TOU8(save->szLastName) << std::endl;
|
std::cout << "\tNew name: " << firstName << " " << lastName;
|
||||||
|
if (nameCheck != 1) std::cout << " (pending approval)";
|
||||||
|
std::cout << std::endl;
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,6 +683,42 @@ bool CNLoginServer::isPasswordCorrect(std::string actualPassword, std::string tr
|
|||||||
return BCrypt::validatePassword(tryPassword, actualPassword);
|
return BCrypt::validatePassword(tryPassword, actualPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CNLoginServer::isNameWheelNameGood(int fnCode, int mnCode, int lnCode, std::string& firstName, std::string& lastName) {
|
||||||
|
if (fnCode >= LoginServer::WheelFirstNames.size()
|
||||||
|
|| mnCode >= LoginServer::WheelMiddleNames.size()
|
||||||
|
|| lnCode >= LoginServer::WheelLastNames.size()) {
|
||||||
|
std::cout << "[WARN] Login Server: Invalid name codes received: " << fnCode << " " << mnCode << " " << lnCode << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// client sends 1 if not selected for these. they point to a single blank space. why.
|
||||||
|
// just change them to 0, which points to an empty string; keeps the code much cleaner
|
||||||
|
if (mnCode == 1) mnCode = 0;
|
||||||
|
if (lnCode == 1) lnCode = 0;
|
||||||
|
|
||||||
|
std::string firstNameFromWheel = LoginServer::WheelFirstNames[fnCode];
|
||||||
|
|
||||||
|
std::string middleNamePart = LoginServer::WheelMiddleNames[mnCode];
|
||||||
|
std::string lastNamePart = LoginServer::WheelLastNames[lnCode];
|
||||||
|
if (mnCode != 0 && middleNamePart[middleNamePart.size() - 1] != ' ') {
|
||||||
|
// If there's a middle name, we need to lowercase the last name
|
||||||
|
std::transform(lastNamePart.begin(), lastNamePart.end(), lastNamePart.begin(), ::tolower);
|
||||||
|
}
|
||||||
|
std::string lastNameFromWheel = middleNamePart + lastNamePart;
|
||||||
|
|
||||||
|
if (firstNameFromWheel.empty() || lastNameFromWheel.empty()) {
|
||||||
|
std::cout << "[WARN] Login Server: Invalid wheel name combo: " << fnCode << " " << mnCode << " " << lnCode << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstName != firstNameFromWheel || lastName != lastNameFromWheel) {
|
||||||
|
std::cout << "[WARN] Login Server: Name wheel mismatch. Expected " << firstNameFromWheel << " " << lastNameFromWheel << ", got " << firstName << " " << lastName << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CNLoginServer::isCharacterNameGood(std::string Firstname, std::string Lastname) {
|
bool CNLoginServer::isCharacterNameGood(std::string Firstname, std::string Lastname) {
|
||||||
//Allow alphanumeric and dot characters in names(disallows dot and space characters at the beginning of a name)
|
//Allow alphanumeric and dot characters in names(disallows dot and space characters at the beginning of a name)
|
||||||
std::regex firstnamecheck(R"(((?! )(?!\.)[a-zA-Z0-9]*\.{0,1}(?!\.+ +)[a-zA-Z0-9]* {0,1}(?! +))*$)");
|
std::regex firstnamecheck(R"(((?! )(?!\.)[a-zA-Z0-9]*\.{0,1}(?!\.+ +)[a-zA-Z0-9]* {0,1}(?! +))*$)");
|
||||||
|
@@ -7,6 +7,12 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
namespace LoginServer {
|
||||||
|
extern std::vector<std::string> WheelFirstNames;
|
||||||
|
extern std::vector<std::string> WheelMiddleNames;
|
||||||
|
extern std::vector<std::string> WheelLastNames;
|
||||||
|
}
|
||||||
|
|
||||||
struct CNLoginData {
|
struct CNLoginData {
|
||||||
int userID;
|
int userID;
|
||||||
time_t lastHeartbeat;
|
time_t lastHeartbeat;
|
||||||
@@ -51,6 +57,7 @@ private:
|
|||||||
static bool isPasswordGood(std::string& password);
|
static bool isPasswordGood(std::string& password);
|
||||||
static bool isPasswordCorrect(std::string actualPassword, std::string tryPassword);
|
static bool isPasswordCorrect(std::string actualPassword, std::string tryPassword);
|
||||||
static bool isAccountInUse(int accountId);
|
static bool isAccountInUse(int accountId);
|
||||||
|
static bool isNameWheelNameGood(int fnCode, int mnCode, int lnCode, std::string& firstName, std::string& lastName);
|
||||||
static bool isCharacterNameGood(std::string Firstname, std::string Lastname);
|
static bool isCharacterNameGood(std::string Firstname, std::string Lastname);
|
||||||
static bool isAuthMethodAllowed(AuthMethod authMethod);
|
static bool isAuthMethodAllowed(AuthMethod authMethod);
|
||||||
static bool checkUsername(CNSocket* sock, std::string& username);
|
static bool checkUsername(CNSocket* sock, std::string& username);
|
||||||
|
@@ -14,6 +14,13 @@ static std::mutex sockLock; // guards socket list
|
|||||||
static std::list<SOCKET> sockets;
|
static std::list<SOCKET> sockets;
|
||||||
static sockaddr_in address;
|
static sockaddr_in address;
|
||||||
|
|
||||||
|
std::vector<std::string> Monitor::chats;
|
||||||
|
std::vector<std::string> Monitor::bcasts;
|
||||||
|
std::vector<std::string> Monitor::emails;
|
||||||
|
std::vector<std::string> Monitor::namereqs;
|
||||||
|
|
||||||
|
using namespace Monitor;
|
||||||
|
|
||||||
static bool transmit(std::list<SOCKET>::iterator& it, char *buff, int len) {
|
static bool transmit(std::list<SOCKET>::iterator& it, char *buff, int len) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int sock = *it;
|
int sock = *it;
|
||||||
@@ -99,15 +106,23 @@ outer:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// chat
|
// chat
|
||||||
for (auto& str : Chat::dump) {
|
for (auto& str : chats) {
|
||||||
n = std::snprintf(buff, sizeof(buff), "chat %s\n", str.c_str());
|
n = std::snprintf(buff, sizeof(buff), "chat %s\n", str.c_str());
|
||||||
|
|
||||||
if (!transmit(it, buff, n))
|
if (!transmit(it, buff, n))
|
||||||
goto outer;
|
goto outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// announcements
|
||||||
|
for (auto& str : bcasts) {
|
||||||
|
n = std::snprintf(buff, sizeof(buff), "bcast %s\n", str.c_str());
|
||||||
|
|
||||||
|
if (!transmit(it, buff, n))
|
||||||
|
goto outer;
|
||||||
|
}
|
||||||
|
|
||||||
// emails
|
// emails
|
||||||
for (auto& str : Email::dump) {
|
for (auto& str : emails) {
|
||||||
n = process_email(buff, str);
|
n = process_email(buff, str);
|
||||||
|
|
||||||
if (!transmit(it, buff, n))
|
if (!transmit(it, buff, n))
|
||||||
@@ -117,14 +132,24 @@ outer:
|
|||||||
goto outer;
|
goto outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// name requests
|
||||||
|
for (auto& str : namereqs) {
|
||||||
|
n = std::snprintf(buff, sizeof(buff), "namereq %s\n", str.c_str());
|
||||||
|
|
||||||
|
if (!transmit(it, buff, n))
|
||||||
|
goto outer;
|
||||||
|
}
|
||||||
|
|
||||||
if (!transmit(it, (char*)"end\n", 4))
|
if (!transmit(it, (char*)"end\n", 4))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chat::dump.clear();
|
chats.clear();
|
||||||
Email::dump.clear();
|
bcasts.clear();
|
||||||
|
emails.clear();
|
||||||
|
namereqs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Monitor::acceptConnection(SOCKET fd, uint16_t revents) {
|
bool Monitor::acceptConnection(SOCKET fd, uint16_t revents) {
|
||||||
|
@@ -3,6 +3,11 @@
|
|||||||
#include "core/Core.hpp"
|
#include "core/Core.hpp"
|
||||||
|
|
||||||
namespace Monitor {
|
namespace Monitor {
|
||||||
|
extern std::vector<std::string> chats;
|
||||||
|
extern std::vector<std::string> bcasts;
|
||||||
|
extern std::vector<std::string> emails;
|
||||||
|
extern std::vector<std::string> namereqs;
|
||||||
|
|
||||||
SOCKET init();
|
SOCKET init();
|
||||||
bool acceptConnection(SOCKET, uint16_t);
|
bool acceptConnection(SOCKET, uint16_t);
|
||||||
};
|
};
|
||||||
|
@@ -12,7 +12,8 @@ bool settings::SANDBOX = true;
|
|||||||
std::string settings::SANDBOXEXTRAPATH = "";
|
std::string settings::SANDBOXEXTRAPATH = "";
|
||||||
|
|
||||||
int settings::LOGINPORT = 23000;
|
int settings::LOGINPORT = 23000;
|
||||||
bool settings::APPROVEALLNAMES = true;
|
bool settings::APPROVEWHEELNAMES = true;
|
||||||
|
bool settings::APPROVECUSTOMNAMES = true;
|
||||||
bool settings::AUTOCREATEACCOUNTS = true;
|
bool settings::AUTOCREATEACCOUNTS = true;
|
||||||
std::string settings::AUTHMETHODS = "password";
|
std::string settings::AUTHMETHODS = "password";
|
||||||
int settings::DBSAVEINTERVAL = 240;
|
int settings::DBSAVEINTERVAL = 240;
|
||||||
@@ -89,7 +90,8 @@ void settings::init() {
|
|||||||
SANDBOX = reader.GetBoolean("", "sandbox", SANDBOX);
|
SANDBOX = reader.GetBoolean("", "sandbox", SANDBOX);
|
||||||
SANDBOXEXTRAPATH = reader.Get("", "sandboxextrapath", SANDBOXEXTRAPATH);
|
SANDBOXEXTRAPATH = reader.Get("", "sandboxextrapath", SANDBOXEXTRAPATH);
|
||||||
LOGINPORT = reader.GetInteger("login", "port", LOGINPORT);
|
LOGINPORT = reader.GetInteger("login", "port", LOGINPORT);
|
||||||
APPROVEALLNAMES = reader.GetBoolean("login", "acceptallcustomnames", APPROVEALLNAMES);
|
APPROVEWHEELNAMES = reader.GetBoolean("login", "acceptallwheelnames", APPROVEWHEELNAMES);
|
||||||
|
APPROVECUSTOMNAMES = reader.GetBoolean("login", "acceptallcustomnames", APPROVECUSTOMNAMES);
|
||||||
AUTOCREATEACCOUNTS = reader.GetBoolean("login", "autocreateaccounts", AUTOCREATEACCOUNTS);
|
AUTOCREATEACCOUNTS = reader.GetBoolean("login", "autocreateaccounts", AUTOCREATEACCOUNTS);
|
||||||
AUTHMETHODS = reader.Get("login", "authmethods", AUTHMETHODS);
|
AUTHMETHODS = reader.Get("login", "authmethods", AUTHMETHODS);
|
||||||
DBSAVEINTERVAL = reader.GetInteger("login", "dbsaveinterval", DBSAVEINTERVAL);
|
DBSAVEINTERVAL = reader.GetInteger("login", "dbsaveinterval", DBSAVEINTERVAL);
|
||||||
|
@@ -9,7 +9,8 @@ namespace settings {
|
|||||||
extern bool SANDBOX;
|
extern bool SANDBOX;
|
||||||
extern std::string SANDBOXEXTRAPATH;
|
extern std::string SANDBOXEXTRAPATH;
|
||||||
extern int LOGINPORT;
|
extern int LOGINPORT;
|
||||||
extern bool APPROVEALLNAMES;
|
extern bool APPROVEWHEELNAMES;
|
||||||
|
extern bool APPROVECUSTOMNAMES;
|
||||||
extern bool AUTOCREATEACCOUNTS;
|
extern bool AUTOCREATEACCOUNTS;
|
||||||
extern std::string AUTHMETHODS;
|
extern std::string AUTHMETHODS;
|
||||||
extern int DBSAVEINTERVAL;
|
extern int DBSAVEINTERVAL;
|
||||||
|
52
win-setup.ps1
Normal file
52
win-setup.ps1
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# Run this first if needed:
|
||||||
|
# Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
|
||||||
|
param (
|
||||||
|
# height of largest column without top bar
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$protocolVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
# check for vscmd
|
||||||
|
if ([string]::IsNullOrEmpty($env:VSCMD_VER)) {
|
||||||
|
Write-Host 'Must be run inside of VS Developer Powershell'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for git
|
||||||
|
try {
|
||||||
|
$git_version = git --version
|
||||||
|
} catch {
|
||||||
|
Write-Host 'git not installed'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# setup vcpkg
|
||||||
|
if (Test-Path -Path 'vcpkg\') {
|
||||||
|
Write-Host 'vcpkg already setup'
|
||||||
|
} else {
|
||||||
|
Write-Host 'Setting up vcpkg...'
|
||||||
|
git clone "https://github.com/microsoft/vcpkg.git"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path -Path 'vcpkg\vcpkg.exe')) {
|
||||||
|
Write-Host 'Bootstrapping vcpkg...'
|
||||||
|
Start-Process -Wait -NoNewWindow -FilePath 'vcpkg\bootstrap-vcpkg.bat' -ArgumentList '-disableMetrics'
|
||||||
|
}
|
||||||
|
|
||||||
|
$env:VCPKG_ROOT='' # ignore msvc's vcpkg root, it doesn't work
|
||||||
|
$vcpkg = (Resolve-Path -Path '.\vcpkg')
|
||||||
|
Write-Host "vcpkg installed to $vcpkg"
|
||||||
|
Start-Process -Wait -NoNewWindow -FilePath 'vcpkg\vcpkg.exe' -ArgumentList 'install sqlite3:x64-windows'
|
||||||
|
|
||||||
|
# setup cmake project
|
||||||
|
if (Test-Path -Path 'build\') {
|
||||||
|
Write-Host 'cmake project already setup';
|
||||||
|
} else {
|
||||||
|
Write-Host 'Setting up cmake project...'
|
||||||
|
Start-Process -Wait -NoNewWindow -FilePath 'cmake' -ArgumentList "-B build -DPROTOCOL_VERSION=$protocolVersion -DCMAKE_TOOLCHAIN_FILE=$vcpkg\scripts\buildsystems\vcpkg.cmake"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host 'Done!'
|
||||||
|
$sln = (Resolve-Path -Path '.\build\OpenFusion.sln')
|
||||||
|
Write-Host "Solution file is at $sln"
|
Reference in New Issue
Block a user