wrapping up for a public release
This commit is contained in:
parent
20ca1cf661
commit
7ca3cfca6e
24
LICENSE.txt
Normal file
24
LICENSE.txt
Normal file
@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org/>
|
||||
2
Makefile
2
Makefile
@ -10,7 +10,7 @@ LFLAGS = -Wl,-t
|
||||
|
||||
DEBUG ?= 0
|
||||
ifneq ($(DEBUG), 0)
|
||||
CFLAGS += -g -O0
|
||||
CFLAGS += -g -Og
|
||||
else
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
|
||||
15
README.md
Normal file
15
README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Tibia 7.7 Query Manager
|
||||
This is a simple query manager designed to support [Tibia Game Server](https://github.com/fusion32/tibia-game), [Tibia Login Server](https://github.com/fusion32/tibia-login), and [Tibia Web Server](https://github.com/fusion32/tibia-web). It uses the SQLite3 3.50.2 amalgamation for a database backend so we can completely avoid having to spin up yet another service for a separate database system, effectively turning the query manager into the database itself. This design choice was made with a single game server in mind. The networking protocol is NOT encrypted at all and won't accept remote connections. For a fully multi-world distributed infrastructure, a distributed database system like PostgreSQL and MySQL/MariaDB should be considered.
|
||||
|
||||
## Compiling
|
||||
Even though there are no Linux specific features being used, it will currently only compile on Linux. It should be simple enough to support compiling on Windows but I don't think it would add any value, considering the game server needs to run on Linux and they need to be both on the same machine. The makefile is very simple and there are **ZERO** dependencies required. You can add the `-j N` switch to make it compile across N processes.
|
||||
```
|
||||
make # build in release mode
|
||||
make DEBUG=1 # build in debug mode
|
||||
make clean # remove `build` directory
|
||||
```
|
||||
|
||||
## Running
|
||||
The query manager will automatically manage the database schema based on files in `sql/` (see `sql/README.txt`), but won't automatically insert any initial data (see `sql/init.sql`). It does have a few configuration options that are loaded from `config.cfg` but the defaults should work for most use cases.
|
||||
|
||||
It is recommended that the query manager is setup as a service. There is a *systemd* configuration file (`tibia-querymanager.service`) in the repository that may be used for that purpose. The process is very similar to the one described in the [Game Server](https://github.com/fusion32/tibia-game) so I won't repeat myself here.
|
||||
@ -8,8 +8,8 @@ HostNameExpireTime = 30m
|
||||
|
||||
# Connection Config
|
||||
UpdateRate = 20
|
||||
QueryManagerPort = 7174
|
||||
QueryManagerPort = 7173
|
||||
QueryManagerPassword = "a6glaf0c"
|
||||
MaxConnections = 50
|
||||
MaxConnectionIdleTime = 60s
|
||||
MaxConnections = 25
|
||||
MaxConnectionIdleTime = 5m
|
||||
MaxConnectionPacketSize = 1M
|
||||
|
||||
103
sql/init.sql
Normal file
103
sql/init.sql
Normal file
@ -0,0 +1,103 @@
|
||||
-- NOTE(fusion): The query manager WON'T automatically run this but the game
|
||||
-- server still requires at least the world config to be able to boot up. It
|
||||
-- is probably a good idea to keep this separated from `schema.sql` and then
|
||||
-- running it with `sqlite3 -echo tibia.db < sql/init.sql`, although it is
|
||||
-- not mandatory.
|
||||
-- Because this isn't automatically managed, all queries are wrapped in a
|
||||
-- transaction to avoid partial writes in case of errors.
|
||||
--==============================================================================
|
||||
BEGIN;
|
||||
|
||||
INSERT INTO Worlds (WorldID, Name, Type, RebootTime, Host, Port, MaxPlayers,
|
||||
PremiumPlayerBuffer, MaxNewbies, PremiumNewbieBuffer)
|
||||
VALUES (1, 'Zanera', 0, 5, 'localhost', 7172, 1000, 100, 300, 100);
|
||||
|
||||
-- 111111/tibia
|
||||
INSERT INTO Accounts (AccountID, Email, Auth)
|
||||
VALUES (111111, '@tibia', X'206699cbc2fae1683118c873d746aa376049cb5923ef0980298bb7acbba527ec9e765668f7a338dffea34acf61a20efb654c1e9c62d35148dba2aeeef8dc7788');
|
||||
|
||||
INSERT INTO Characters (WorldID, CharacterID, AccountID, Name, Sex)
|
||||
VALUES (1, 1, 111111, 'Gamemaster', 1), (1, 2, 111111, 'Player', 1);
|
||||
|
||||
INSERT INTO CharacterRights (CharacterID, Right)
|
||||
VALUES
|
||||
(1, 'NOTATION'),
|
||||
(1, 'NAMELOCK'),
|
||||
(1, 'STATEMENT_REPORT'),
|
||||
(1, 'BANISHMENT'),
|
||||
(1, 'FINAL_WARNING'),
|
||||
(1, 'IP_BANISHMENT'),
|
||||
(1, 'KICK'),
|
||||
(1, 'HOME_TELEPORT'),
|
||||
(1, 'GAMEMASTER_BROADCAST'),
|
||||
(1, 'ANONYMOUS_BROADCAST'),
|
||||
(1, 'NO_BANISHMENT'),
|
||||
(1, 'ALLOW_MULTICLIENT'),
|
||||
(1, 'LOG_COMMUNICATION'),
|
||||
(1, 'READ_GAMEMASTER_CHANNEL'),
|
||||
(1, 'READ_TUTOR_CHANNEL'),
|
||||
(1, 'HIGHLIGHT_HELP_CHANNEL'),
|
||||
(1, 'SEND_BUGREPORTS'),
|
||||
(1, 'NAME_INSULTING'),
|
||||
(1, 'NAME_SENTENCE'),
|
||||
(1, 'NAME_NONSENSICAL_LETTERS'),
|
||||
(1, 'NAME_BADLY_FORMATTED'),
|
||||
(1, 'NAME_NO_PERSON'),
|
||||
(1, 'NAME_CELEBRITY'),
|
||||
(1, 'NAME_COUNTRY'),
|
||||
(1, 'NAME_FAKE_IDENTITY'),
|
||||
(1, 'NAME_FAKE_POSITION'),
|
||||
(1, 'STATEMENT_INSULTING'),
|
||||
(1, 'STATEMENT_SPAMMING'),
|
||||
(1, 'STATEMENT_ADVERT_OFFTOPIC'),
|
||||
(1, 'STATEMENT_ADVERT_MONEY'),
|
||||
(1, 'STATEMENT_NON_ENGLISH'),
|
||||
(1, 'STATEMENT_CHANNEL_OFFTOPIC'),
|
||||
(1, 'STATEMENT_VIOLATION_INCITING'),
|
||||
(1, 'CHEATING_BUG_ABUSE'),
|
||||
(1, 'CHEATING_GAME_WEAKNESS'),
|
||||
(1, 'CHEATING_MACRO_USE'),
|
||||
(1, 'CHEATING_MODIFIED_CLIENT'),
|
||||
(1, 'CHEATING_HACKING'),
|
||||
(1, 'CHEATING_MULTI_CLIENT'),
|
||||
(1, 'CHEATING_ACCOUNT_TRADING'),
|
||||
(1, 'CHEATING_ACCOUNT_SHARING'),
|
||||
(1, 'GAMEMASTER_THREATENING'),
|
||||
(1, 'GAMEMASTER_PRETENDING'),
|
||||
(1, 'GAMEMASTER_INFLUENCE'),
|
||||
(1, 'GAMEMASTER_FALSE_REPORTS'),
|
||||
(1, 'KILLING_EXCESSIVE_UNJUSTIFIED'),
|
||||
(1, 'DESTRUCTIVE_BEHAVIOUR'),
|
||||
(1, 'SPOILING_AUCTION'),
|
||||
(1, 'INVALID_PAYMENT'),
|
||||
(1, 'TELEPORT_TO_CHARACTER'),
|
||||
(1, 'TELEPORT_TO_MARK'),
|
||||
(1, 'TELEPORT_VERTICAL'),
|
||||
(1, 'TELEPORT_TO_COORDINATE'),
|
||||
(1, 'LEVITATE'),
|
||||
(1, 'SPECIAL_MOVEUSE'),
|
||||
(1, 'MODIFY_GOSTRENGTH'),
|
||||
(1, 'SHOW_COORDINATE'),
|
||||
(1, 'RETRIEVE'),
|
||||
(1, 'ENTER_HOUSES'),
|
||||
(1, 'OPEN_NAMEDOORS'),
|
||||
(1, 'INVULNERABLE'),
|
||||
(1, 'UNLIMITED_MANA'),
|
||||
(1, 'KEEP_INVENTORY'),
|
||||
(1, 'ALL_SPELLS'),
|
||||
(1, 'UNLIMITED_CAPACITY'),
|
||||
(1, 'ATTACK_EVERYWHERE'),
|
||||
(1, 'NO_LOGOUT_BLOCK'),
|
||||
(1, 'GAMEMASTER_OUTFIT'),
|
||||
(1, 'ILLUMINATE'),
|
||||
(1, 'CHANGE_PROFESSION'),
|
||||
(1, 'IGNORED_BY_MONSTERS'),
|
||||
(1, 'SHOW_KEYHOLE_NUMBERS'),
|
||||
(1, 'CREATE_OBJECTS'),
|
||||
(1, 'CREATE_MONEY'),
|
||||
(1, 'CREATE_MONSTERS'),
|
||||
(1, 'CHANGE_SKILLS'),
|
||||
(1, 'CLEANUP_FIELDS'),
|
||||
(1, 'NO_STATISTICS');
|
||||
|
||||
COMMIT;
|
||||
114
sql/schema.sql
114
sql/schema.sql
@ -54,6 +54,16 @@ CREATE INDEX IF NOT EXISTS CharactersAccountIndex
|
||||
CREATE INDEX IF NOT EXISTS CharactersGuildIndex
|
||||
ON Characters(Guild, Rank);
|
||||
|
||||
/*
|
||||
-- TODO(fusion): Have group rights instead of adding individual rights to characters?
|
||||
ALTER TABLE Characters ADD GroupID INTEGER NOT NULL;
|
||||
CREATE TABLE IF NOT EXISTS CharacterRights (
|
||||
GroupID INTEGER NOT NULL,
|
||||
Right TEXT NOT NULL COLLATE NOCASE,
|
||||
PRIMARY KEY(GroupID, Right)
|
||||
);
|
||||
*/
|
||||
|
||||
CREATE TABLE IF NOT EXISTS CharacterRights (
|
||||
CharacterID INTEGER NOT NULL,
|
||||
Right TEXT NOT NULL COLLATE NOCASE,
|
||||
@ -262,107 +272,3 @@ CREATE TABLE IF NOT EXISTS OnlineCharacters (
|
||||
Profession TEXT NOT NULL,
|
||||
PRIMARY KEY (WorldID, Name)
|
||||
);
|
||||
|
||||
-- REMOVE(fusion): Testing Data.
|
||||
--==============================================================================
|
||||
INSERT INTO Worlds (WorldID, Name, Type, RebootTime, Host, Port, MaxPlayers,
|
||||
PremiumPlayerBuffer, MaxNewbies, PremiumNewbieBuffer)
|
||||
VALUES (1, 'Zanera', 0, 5, 'localhost', 7172, 1000, 100, 300, 100);
|
||||
|
||||
-- 111111/tibia
|
||||
INSERT INTO Accounts (AccountID, Email, Auth)
|
||||
VALUES (111111, '@tibia', X'206699cbc2fae1683118c873d746aa376049cb5923ef0980298bb7acbba527ec9e765668f7a338dffea34acf61a20efb654c1e9c62d35148dba2aeeef8dc7788');
|
||||
|
||||
INSERT INTO Characters (WorldID, CharacterID, AccountID, Name, Sex)
|
||||
VALUES (1, 1, 111111, 'Gamemaster', 1), (1, 2, 111111, 'Player', 1);
|
||||
|
||||
/*
|
||||
-- TODO(fusion): Have group rights instead of adding individual rights to characters?
|
||||
ALTER TABLE Characters ADD GroupID INTEGER NOT NULL;
|
||||
CREATE TABLE IF NOT EXISTS CharacterRights (
|
||||
GroupID INTEGER NOT NULL,
|
||||
Right TEXT NOT NULL COLLATE NOCASE,
|
||||
PRIMARY KEY(GroupID, Right)
|
||||
);
|
||||
*/
|
||||
|
||||
INSERT INTO CharacterRights (CharacterID, Right)
|
||||
VALUES
|
||||
(1, 'NOTATION'),
|
||||
(1, 'NAMELOCK'),
|
||||
(1, 'STATEMENT_REPORT'),
|
||||
(1, 'BANISHMENT'),
|
||||
(1, 'FINAL_WARNING'),
|
||||
(1, 'IP_BANISHMENT'),
|
||||
(1, 'KICK'),
|
||||
(1, 'HOME_TELEPORT'),
|
||||
(1, 'GAMEMASTER_BROADCAST'),
|
||||
(1, 'ANONYMOUS_BROADCAST'),
|
||||
(1, 'NO_BANISHMENT'),
|
||||
(1, 'ALLOW_MULTICLIENT'),
|
||||
(1, 'LOG_COMMUNICATION'),
|
||||
(1, 'READ_GAMEMASTER_CHANNEL'),
|
||||
(1, 'READ_TUTOR_CHANNEL'),
|
||||
(1, 'HIGHLIGHT_HELP_CHANNEL'),
|
||||
(1, 'SEND_BUGREPORTS'),
|
||||
(1, 'NAME_INSULTING'),
|
||||
(1, 'NAME_SENTENCE'),
|
||||
(1, 'NAME_NONSENSICAL_LETTERS'),
|
||||
(1, 'NAME_BADLY_FORMATTED'),
|
||||
(1, 'NAME_NO_PERSON'),
|
||||
(1, 'NAME_CELEBRITY'),
|
||||
(1, 'NAME_COUNTRY'),
|
||||
(1, 'NAME_FAKE_IDENTITY'),
|
||||
(1, 'NAME_FAKE_POSITION'),
|
||||
(1, 'STATEMENT_INSULTING'),
|
||||
(1, 'STATEMENT_SPAMMING'),
|
||||
(1, 'STATEMENT_ADVERT_OFFTOPIC'),
|
||||
(1, 'STATEMENT_ADVERT_MONEY'),
|
||||
(1, 'STATEMENT_NON_ENGLISH'),
|
||||
(1, 'STATEMENT_CHANNEL_OFFTOPIC'),
|
||||
(1, 'STATEMENT_VIOLATION_INCITING'),
|
||||
(1, 'CHEATING_BUG_ABUSE'),
|
||||
(1, 'CHEATING_GAME_WEAKNESS'),
|
||||
(1, 'CHEATING_MACRO_USE'),
|
||||
(1, 'CHEATING_MODIFIED_CLIENT'),
|
||||
(1, 'CHEATING_HACKING'),
|
||||
(1, 'CHEATING_MULTI_CLIENT'),
|
||||
(1, 'CHEATING_ACCOUNT_TRADING'),
|
||||
(1, 'CHEATING_ACCOUNT_SHARING'),
|
||||
(1, 'GAMEMASTER_THREATENING'),
|
||||
(1, 'GAMEMASTER_PRETENDING'),
|
||||
(1, 'GAMEMASTER_INFLUENCE'),
|
||||
(1, 'GAMEMASTER_FALSE_REPORTS'),
|
||||
(1, 'KILLING_EXCESSIVE_UNJUSTIFIED'),
|
||||
(1, 'DESTRUCTIVE_BEHAVIOUR'),
|
||||
(1, 'SPOILING_AUCTION'),
|
||||
(1, 'INVALID_PAYMENT'),
|
||||
(1, 'TELEPORT_TO_CHARACTER'),
|
||||
(1, 'TELEPORT_TO_MARK'),
|
||||
(1, 'TELEPORT_VERTICAL'),
|
||||
(1, 'TELEPORT_TO_COORDINATE'),
|
||||
(1, 'LEVITATE'),
|
||||
(1, 'SPECIAL_MOVEUSE'),
|
||||
(1, 'MODIFY_GOSTRENGTH'),
|
||||
(1, 'SHOW_COORDINATE'),
|
||||
(1, 'RETRIEVE'),
|
||||
(1, 'ENTER_HOUSES'),
|
||||
(1, 'OPEN_NAMEDOORS'),
|
||||
(1, 'INVULNERABLE'),
|
||||
(1, 'UNLIMITED_MANA'),
|
||||
(1, 'KEEP_INVENTORY'),
|
||||
(1, 'ALL_SPELLS'),
|
||||
(1, 'UNLIMITED_CAPACITY'),
|
||||
(1, 'ATTACK_EVERYWHERE'),
|
||||
(1, 'NO_LOGOUT_BLOCK'),
|
||||
(1, 'GAMEMASTER_OUTFIT'),
|
||||
(1, 'ILLUMINATE'),
|
||||
(1, 'CHANGE_PROFESSION'),
|
||||
(1, 'IGNORED_BY_MONSTERS'),
|
||||
(1, 'SHOW_KEYHOLE_NUMBERS'),
|
||||
(1, 'CREATE_OBJECTS'),
|
||||
(1, 'CREATE_MONEY'),
|
||||
(1, 'CREATE_MONSTERS'),
|
||||
(1, 'CHANGE_SKILLS'),
|
||||
(1, 'CLEANUP_FIELDS'),
|
||||
(1, 'NO_STATISTICS');
|
||||
|
||||
@ -2042,7 +2042,7 @@ bool MergeKillStatistics(int WorldID, int NumStats, TKillStatistics *Stats){
|
||||
"INSERT INTO KillStatistics (WorldID, RaceName, TimesKilled, PlayersKilled)"
|
||||
" VALUES (?1, ?2, ?3, ?4)"
|
||||
" ON CONFLICT DO UPDATE SET TimesKilled = TimesKilled + Excluded.TimesKilled,"
|
||||
" PlayersKilled = PlayersKilled + Excluded.TimesKilled");
|
||||
" PlayersKilled = PlayersKilled + Excluded.PlayersKilled");
|
||||
if(Stmt == NULL){
|
||||
LOG_ERR("Failed to prepare query");
|
||||
return false;
|
||||
|
||||
@ -44,6 +44,7 @@ void LogAdd(const char *Prefix, const char *Format, ...){
|
||||
LocalTime.tm_year + 1900, LocalTime.tm_mon + 1, LocalTime.tm_mday,
|
||||
LocalTime.tm_hour, LocalTime.tm_min, LocalTime.tm_sec,
|
||||
Prefix, Entry);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,6 +64,7 @@ void LogAddVerbose(const char *Prefix, const char *Function,
|
||||
LocalTime.tm_year + 1900, LocalTime.tm_mon + 1, LocalTime.tm_mday,
|
||||
LocalTime.tm_hour, LocalTime.tm_min, LocalTime.tm_sec,
|
||||
Prefix, Function, Entry);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21
tibia-querymanager.service
Normal file
21
tibia-querymanager.service
Normal file
@ -0,0 +1,21 @@
|
||||
# Basic SYSTEMD service file for the Tibia Query Manager
|
||||
|
||||
[Unit]
|
||||
Description=Tibia Query Manager
|
||||
After=network.target
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=tibia-querymanager
|
||||
Group=tibia-querymanager
|
||||
ExecStart=/opt/tibia/querymanager/querymanager
|
||||
WorkingDirectory=/opt/tibia/querymanager/
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
LimitCORE=infinity
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=%n
|
||||
33
tools/pwdhash.go
Normal file
33
tools/pwdhash.go
Normal file
@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) <= 1 {
|
||||
fmt.Printf("usage: pwdhash PASSWORD\n")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("password = \"%v\"\n", os.Args[1])
|
||||
|
||||
var salt [32]byte
|
||||
if n, err := rand.Read(salt[:]); err != nil || n != 32 {
|
||||
fmt.Printf("Failed to generate salt: %v\n", err)
|
||||
}
|
||||
|
||||
secret := sha256.Sum256([]byte(os.Args[1]))
|
||||
for i := 0; i < 32; i += 1 {
|
||||
secret[i] ^= salt[i]
|
||||
}
|
||||
|
||||
pwdhash := sha256.Sum256(secret[:])
|
||||
|
||||
fmt.Printf("pwdhash = %v\n", hex.EncodeToString(pwdhash[:]))
|
||||
fmt.Printf("salt = %v\n", hex.EncodeToString(salt[:]))
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user