Initial commit

ZnoteX / Commit #5

Commit Initial commit

Alex Alex committed 01/10/2026 09:20 main Full upload
481 files +128,311 -0
A docker/mysql/schemas/tfs_10.sql +352-0 View file
@@ -0,0 +1,352 @@
1+-- The Forgotten Server (TFS) 1.1 database schema.
2+-- Source: https://github.com/otland/forgottenserver/blob/v1.1/schema.sql
3+-- License: GPL-2.0. Covers ZnoteX's TFS_10 engine choice ("TFS 1.1 - 1.4.2").
4+
5+CREATE TABLE IF NOT EXISTS `accounts` (
6+ `id` int(11) NOT NULL AUTO_INCREMENT,
7+ `name` varchar(32) NOT NULL,
8+ `password` char(40) NOT NULL,
9+ `type` int(11) NOT NULL DEFAULT '1',
10+ `premdays` int(11) NOT NULL DEFAULT '0',
11+ `lastday` int(10) unsigned NOT NULL DEFAULT '0',
12+ `email` varchar(255) NOT NULL DEFAULT '',
13+ `creation` int(11) NOT NULL DEFAULT '0',
14+ PRIMARY KEY (`id`),
15+ UNIQUE KEY `name` (`name`)
16+) ENGINE=InnoDB;
17+
18+CREATE TABLE IF NOT EXISTS `players` (
19+ `id` int(11) NOT NULL AUTO_INCREMENT,
20+ `name` varchar(255) NOT NULL,
21+ `group_id` int(11) NOT NULL DEFAULT '1',
22+ `account_id` int(11) NOT NULL DEFAULT '0',
23+ `level` int(11) NOT NULL DEFAULT '1',
24+ `vocation` int(11) NOT NULL DEFAULT '0',
25+ `health` int(11) NOT NULL DEFAULT '150',
26+ `healthmax` int(11) NOT NULL DEFAULT '150',
27+ `experience` bigint(20) NOT NULL DEFAULT '0',
28+ `lookbody` int(11) NOT NULL DEFAULT '0',
29+ `lookfeet` int(11) NOT NULL DEFAULT '0',
30+ `lookhead` int(11) NOT NULL DEFAULT '0',
31+ `looklegs` int(11) NOT NULL DEFAULT '0',
32+ `looktype` int(11) NOT NULL DEFAULT '136',
33+ `lookaddons` int(11) NOT NULL DEFAULT '0',
34+ `maglevel` int(11) NOT NULL DEFAULT '0',
35+ `mana` int(11) NOT NULL DEFAULT '0',
36+ `manamax` int(11) NOT NULL DEFAULT '0',
37+ `manaspent` int(11) unsigned NOT NULL DEFAULT '0',
38+ `soul` int(10) unsigned NOT NULL DEFAULT '0',
39+ `town_id` int(11) NOT NULL DEFAULT '0',
40+ `posx` int(11) NOT NULL DEFAULT '0',
41+ `posy` int(11) NOT NULL DEFAULT '0',
42+ `posz` int(11) NOT NULL DEFAULT '0',
43+ `conditions` blob NOT NULL,
44+ `cap` int(11) NOT NULL DEFAULT '0',
45+ `sex` int(11) NOT NULL DEFAULT '0',
46+ `lastlogin` bigint(20) unsigned NOT NULL DEFAULT '0',
47+ `lastip` int(10) unsigned NOT NULL DEFAULT '0',
48+ `save` tinyint(1) NOT NULL DEFAULT '1',
49+ `skull` tinyint(1) NOT NULL DEFAULT '0',
50+ `skulltime` int(11) NOT NULL DEFAULT '0',
51+ `lastlogout` bigint(20) unsigned NOT NULL DEFAULT '0',
52+ `blessings` tinyint(2) NOT NULL DEFAULT '0',
53+ `onlinetime` int(11) NOT NULL DEFAULT '0',
54+ `deletion` bigint(15) NOT NULL DEFAULT '0',
55+ `balance` bigint(20) unsigned NOT NULL DEFAULT '0',
56+ `offlinetraining_time` smallint(5) unsigned NOT NULL DEFAULT '43200',
57+ `offlinetraining_skill` int(11) NOT NULL DEFAULT '-1',
58+ `stamina` smallint(5) unsigned NOT NULL DEFAULT '2520',
59+ `skill_fist` int(10) unsigned NOT NULL DEFAULT 10,
60+ `skill_fist_tries` bigint(20) unsigned NOT NULL DEFAULT 0,
61+ `skill_club` int(10) unsigned NOT NULL DEFAULT 10,
62+ `skill_club_tries` bigint(20) unsigned NOT NULL DEFAULT 0,
63+ `skill_sword` int(10) unsigned NOT NULL DEFAULT 10,
64+ `skill_sword_tries` bigint(20) unsigned NOT NULL DEFAULT 0,
65+ `skill_axe` int(10) unsigned NOT NULL DEFAULT 10,
66+ `skill_axe_tries` bigint(20) unsigned NOT NULL DEFAULT 0,
67+ `skill_dist` int(10) unsigned NOT NULL DEFAULT 10,
68+ `skill_dist_tries` bigint(20) unsigned NOT NULL DEFAULT 0,
69+ `skill_shielding` int(10) unsigned NOT NULL DEFAULT 10,
70+ `skill_shielding_tries` bigint(20) unsigned NOT NULL DEFAULT 0,
71+ `skill_fishing` int(10) unsigned NOT NULL DEFAULT 10,
72+ `skill_fishing_tries` bigint(20) unsigned NOT NULL DEFAULT 0,
73+ PRIMARY KEY (`id`),
74+ UNIQUE KEY `name` (`name`),
75+ FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
76+ KEY `vocation` (`vocation`)
77+) ENGINE=InnoDB;
78+
79+CREATE TABLE IF NOT EXISTS `account_bans` (
80+ `account_id` int(11) NOT NULL,
81+ `reason` varchar(255) NOT NULL,
82+ `banned_at` bigint(20) NOT NULL,
83+ `expires_at` bigint(20) NOT NULL,
84+ `banned_by` int(11) NOT NULL,
85+ PRIMARY KEY (`account_id`),
86+ FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
87+ FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
88+) ENGINE=InnoDB;
89+
90+CREATE TABLE IF NOT EXISTS `account_ban_history` (
91+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
92+ `account_id` int(11) NOT NULL,
93+ `reason` varchar(255) NOT NULL,
94+ `banned_at` bigint(20) NOT NULL,
95+ `expired_at` bigint(20) NOT NULL,
96+ `banned_by` int(11) NOT NULL,
97+ PRIMARY KEY (`id`),
98+ FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
99+ FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
100+) ENGINE=InnoDB;
101+
102+CREATE TABLE IF NOT EXISTS `ip_bans` (
103+ `ip` int(10) unsigned NOT NULL,
104+ `reason` varchar(255) NOT NULL,
105+ `banned_at` bigint(20) NOT NULL,
106+ `expires_at` bigint(20) NOT NULL,
107+ `banned_by` int(11) NOT NULL,
108+ PRIMARY KEY (`ip`),
109+ FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
110+) ENGINE=InnoDB;
111+
112+CREATE TABLE IF NOT EXISTS `player_namelocks` (
113+ `player_id` int(11) NOT NULL,
114+ `reason` varchar(255) NOT NULL,
115+ `namelocked_at` bigint(20) NOT NULL,
116+ `namelocked_by` int(11) NOT NULL,
117+ PRIMARY KEY (`player_id`),
118+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
119+ FOREIGN KEY (`namelocked_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
120+) ENGINE=InnoDB;
121+
122+CREATE TABLE IF NOT EXISTS `account_viplist` (
123+ `account_id` int(11) NOT NULL COMMENT 'id of account whose viplist entry it is',
124+ `player_id` int(11) NOT NULL COMMENT 'id of target player of viplist entry',
125+ `description` varchar(128) NOT NULL DEFAULT '',
126+ `icon` tinyint(2) unsigned NOT NULL DEFAULT '0',
127+ `notify` tinyint(1) NOT NULL DEFAULT '0',
128+ UNIQUE KEY `account_player_index` (`account_id`,`player_id`),
129+ FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
130+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE
131+) ENGINE=InnoDB;
132+
133+CREATE TABLE IF NOT EXISTS `guilds` (
134+ `id` int(11) NOT NULL AUTO_INCREMENT,
135+ `name` varchar(255) NOT NULL,
136+ `ownerid` int(11) NOT NULL,
137+ `creationdata` int(11) NOT NULL,
138+ `motd` varchar(255) NOT NULL DEFAULT '',
139+ PRIMARY KEY (`id`),
140+ UNIQUE KEY (`name`),
141+ UNIQUE KEY (`ownerid`),
142+ FOREIGN KEY (`ownerid`) REFERENCES `players`(`id`) ON DELETE CASCADE
143+) ENGINE=InnoDB;
144+
145+CREATE TABLE IF NOT EXISTS `guild_invites` (
146+ `player_id` int(11) NOT NULL DEFAULT '0',
147+ `guild_id` int(11) NOT NULL DEFAULT '0',
148+ PRIMARY KEY (`player_id`,`guild_id`),
149+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE,
150+ FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE
151+) ENGINE=InnoDB;
152+
153+CREATE TABLE IF NOT EXISTS `guild_ranks` (
154+ `id` int(11) NOT NULL AUTO_INCREMENT,
155+ `guild_id` int(11) NOT NULL COMMENT 'guild',
156+ `name` varchar(255) NOT NULL COMMENT 'rank name',
157+ `level` int(11) NOT NULL COMMENT 'rank level - leader, vice, member, maybe something else',
158+ PRIMARY KEY (`id`),
159+ FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE
160+) ENGINE=InnoDB;
161+
162+CREATE TABLE IF NOT EXISTS `guild_membership` (
163+ `player_id` int(11) NOT NULL,
164+ `guild_id` int(11) NOT NULL,
165+ `rank_id` int(11) NOT NULL,
166+ `nick` varchar(15) NOT NULL DEFAULT '',
167+ PRIMARY KEY (`player_id`),
168+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
169+ FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
170+ FOREIGN KEY (`rank_id`) REFERENCES `guild_ranks` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
171+) ENGINE=InnoDB;
172+
173+CREATE TABLE IF NOT EXISTS `guild_wars` (
174+ `id` int(11) NOT NULL AUTO_INCREMENT,
175+ `guild1` int(11) NOT NULL DEFAULT '0',
176+ `guild2` int(11) NOT NULL DEFAULT '0',
177+ `name1` varchar(255) NOT NULL,
178+ `name2` varchar(255) NOT NULL,
179+ `status` tinyint(2) NOT NULL DEFAULT '0',
180+ `started` bigint(15) NOT NULL DEFAULT '0',
181+ `ended` bigint(15) NOT NULL DEFAULT '0',
182+ PRIMARY KEY (`id`),
183+ KEY `guild1` (`guild1`),
184+ KEY `guild2` (`guild2`)
185+) ENGINE=InnoDB;
186+
187+CREATE TABLE IF NOT EXISTS `guildwar_kills` (
188+ `id` int(11) NOT NULL AUTO_INCREMENT,
189+ `killer` varchar(50) NOT NULL,
190+ `target` varchar(50) NOT NULL,
191+ `killerguild` int(11) NOT NULL DEFAULT '0',
192+ `targetguild` int(11) NOT NULL DEFAULT '0',
193+ `warid` int(11) NOT NULL DEFAULT '0',
194+ `time` bigint(15) NOT NULL,
195+ PRIMARY KEY (`id`),
196+ FOREIGN KEY (`warid`) REFERENCES `guild_wars` (`id`) ON DELETE CASCADE
197+) ENGINE=InnoDB;
198+
199+CREATE TABLE IF NOT EXISTS `houses` (
200+ `id` int(11) NOT NULL AUTO_INCREMENT,
201+ `owner` int(11) NOT NULL,
202+ `paid` int(10) unsigned NOT NULL DEFAULT '0',
203+ `warnings` int(11) NOT NULL DEFAULT '0',
204+ `name` varchar(255) NOT NULL,
205+ `rent` int(11) NOT NULL DEFAULT '0',
206+ `town_id` int(11) NOT NULL DEFAULT '0',
207+ `bid` int(11) NOT NULL DEFAULT '0',
208+ `bid_end` int(11) NOT NULL DEFAULT '0',
209+ `last_bid` int(11) NOT NULL DEFAULT '0',
210+ `highest_bidder` int(11) NOT NULL DEFAULT '0',
211+ `size` int(11) NOT NULL DEFAULT '0',
212+ `beds` int(11) NOT NULL DEFAULT '0',
213+ PRIMARY KEY (`id`),
214+ KEY `owner` (`owner`),
215+ KEY `town_id` (`town_id`)
216+) ENGINE=InnoDB;
217+
218+CREATE TABLE IF NOT EXISTS `house_lists` (
219+ `house_id` int(11) NOT NULL,
220+ `listid` int(11) NOT NULL,
221+ `list` text NOT NULL,
222+ FOREIGN KEY (`house_id`) REFERENCES `houses` (`id`) ON DELETE CASCADE
223+) ENGINE=InnoDB;
224+
225+CREATE TABLE IF NOT EXISTS `market_history` (
226+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
227+ `player_id` int(11) NOT NULL,
228+ `sale` tinyint(1) NOT NULL DEFAULT '0',
229+ `itemtype` int(10) unsigned NOT NULL,
230+ `amount` smallint(5) unsigned NOT NULL,
231+ `price` int(10) unsigned NOT NULL DEFAULT '0',
232+ `expires_at` bigint(20) unsigned NOT NULL,
233+ `inserted` bigint(20) unsigned NOT NULL,
234+ `state` tinyint(1) unsigned NOT NULL,
235+ PRIMARY KEY (`id`),
236+ KEY `player_id` (`player_id`, `sale`),
237+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
238+) ENGINE=InnoDB;
239+
240+CREATE TABLE IF NOT EXISTS `market_offers` (
241+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
242+ `player_id` int(11) NOT NULL,
243+ `sale` tinyint(1) NOT NULL DEFAULT '0',
244+ `itemtype` int(10) unsigned NOT NULL,
245+ `amount` smallint(5) unsigned NOT NULL,
246+ `created` bigint(20) unsigned NOT NULL,
247+ `anonymous` tinyint(1) NOT NULL DEFAULT '0',
248+ `price` int(10) unsigned NOT NULL DEFAULT '0',
249+ PRIMARY KEY (`id`),
250+ KEY `sale` (`sale`,`itemtype`),
251+ KEY `created` (`created`),
252+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
253+) ENGINE=InnoDB;
254+
255+CREATE TABLE IF NOT EXISTS `players_online` (
256+ `player_id` int(11) NOT NULL,
257+ PRIMARY KEY (`player_id`)
258+) ENGINE=MEMORY;
259+
260+CREATE TABLE IF NOT EXISTS `player_deaths` (
261+ `player_id` int(11) NOT NULL,
262+ `time` bigint(20) unsigned NOT NULL DEFAULT '0',
263+ `level` int(11) NOT NULL DEFAULT '1',
264+ `killed_by` varchar(255) NOT NULL,
265+ `is_player` tinyint(1) NOT NULL DEFAULT '1',
266+ `mostdamage_by` varchar(100) NOT NULL,
267+ `mostdamage_is_player` tinyint(1) NOT NULL DEFAULT '0',
268+ `unjustified` tinyint(1) NOT NULL DEFAULT '0',
269+ `mostdamage_unjustified` tinyint(1) NOT NULL DEFAULT '0',
270+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE,
271+ KEY `killed_by` (`killed_by`),
272+ KEY `mostdamage_by` (`mostdamage_by`)
273+) ENGINE=InnoDB;
274+
275+CREATE TABLE IF NOT EXISTS `player_depotitems` (
276+ `player_id` int(11) NOT NULL,
277+ `sid` int(11) NOT NULL COMMENT 'any given range eg 0-100 will be reserved for depot lockers and all > 100 will be then normal items inside depots',
278+ `pid` int(11) NOT NULL DEFAULT '0',
279+ `itemtype` smallint(6) NOT NULL,
280+ `count` smallint(5) NOT NULL DEFAULT '0',
281+ `attributes` blob NOT NULL,
282+ UNIQUE KEY `player_id_2` (`player_id`, `sid`),
283+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
284+) ENGINE=InnoDB;
285+
286+CREATE TABLE IF NOT EXISTS `player_inboxitems` (
287+ `player_id` int(11) NOT NULL,
288+ `sid` int(11) NOT NULL,
289+ `pid` int(11) NOT NULL DEFAULT '0',
290+ `itemtype` smallint(6) NOT NULL,
291+ `count` smallint(5) NOT NULL DEFAULT '0',
292+ `attributes` blob NOT NULL,
293+ UNIQUE KEY `player_id_2` (`player_id`, `sid`),
294+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
295+) ENGINE=InnoDB;
296+
297+CREATE TABLE IF NOT EXISTS `player_items` (
298+ `player_id` int(11) NOT NULL DEFAULT '0',
299+ `pid` int(11) NOT NULL DEFAULT '0',
300+ `sid` int(11) NOT NULL DEFAULT '0',
301+ `itemtype` smallint(6) NOT NULL DEFAULT '0',
302+ `count` smallint(5) NOT NULL DEFAULT '0',
303+ `attributes` blob NOT NULL,
304+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE,
305+ KEY `sid` (`sid`)
306+) ENGINE=InnoDB;
307+
308+CREATE TABLE IF NOT EXISTS `player_spells` (
309+ `player_id` int(11) NOT NULL,
310+ `name` varchar(255) NOT NULL,
311+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
312+) ENGINE=InnoDB;
313+
314+CREATE TABLE IF NOT EXISTS `player_storage` (
315+ `player_id` int(11) NOT NULL DEFAULT '0',
316+ `key` int(10) unsigned NOT NULL DEFAULT '0',
317+ `value` int(11) NOT NULL DEFAULT '0',
318+ PRIMARY KEY (`player_id`,`key`),
319+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
320+) ENGINE=InnoDB;
321+
322+CREATE TABLE IF NOT EXISTS `server_config` (
323+ `config` varchar(50) NOT NULL,
324+ `value` varchar(256) NOT NULL DEFAULT '',
325+ PRIMARY KEY `config` (`config`)
326+) ENGINE=InnoDB;
327+
328+INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '18'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0');
329+
330+CREATE TABLE IF NOT EXISTS `tile_store` (
331+ `house_id` int(11) NOT NULL,
332+ `data` longblob NOT NULL,
333+ FOREIGN KEY (`house_id`) REFERENCES `houses` (`id`) ON DELETE CASCADE
334+) ENGINE=InnoDB;
335+
336+DROP TRIGGER IF EXISTS `ondelete_players`;
337+DROP TRIGGER IF EXISTS `oncreate_guilds`;
338+
339+DELIMITER //
340+CREATE TRIGGER `ondelete_players` BEFORE DELETE ON `players`
341+ FOR EACH ROW BEGIN
342+ UPDATE `houses` SET `owner` = 0 WHERE `owner` = OLD.`id`;
343+END
344+//
345+CREATE TRIGGER `oncreate_guilds` AFTER INSERT ON `guilds`
346+ FOR EACH ROW BEGIN
347+ INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('the Leader', 3, NEW.`id`);
348+ INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('a Vice-Leader', 2, NEW.`id`);
349+ INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('a Member', 1, NEW.`id`);
350+END
351+//
352+DELIMITER ;
A docker/mysql/schemas/tfs_16.sql +416-0 View file
@@ -0,0 +1,416 @@
1+-- The Forgotten Server (TFS) 1.6 database schema.
2+-- Source: https://github.com/otland/forgottenserver/blob/v1.6/schema.sql
3+-- License: GPL-2.0. Covers ZnoteX's TFS_16 engine choice.
4+
5+CREATE TABLE IF NOT EXISTS `accounts` (
6+ `id` int NOT NULL AUTO_INCREMENT,
7+ `name` varchar(32) NOT NULL,
8+ `password` char(40) NOT NULL,
9+ `secret` char(16) DEFAULT NULL,
10+ `type` int NOT NULL DEFAULT '1',
11+ `premium_ends_at` int unsigned NOT NULL DEFAULT '0',
12+ `email` varchar(255) NOT NULL DEFAULT '',
13+ `creation` int NOT NULL DEFAULT '0',
14+ PRIMARY KEY (`id`),
15+ UNIQUE KEY `name` (`name`)
16+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
17+
18+CREATE TABLE IF NOT EXISTS `players` (
19+ `id` int NOT NULL AUTO_INCREMENT,
20+ `name` varchar(255) NOT NULL,
21+ `group_id` int NOT NULL DEFAULT '1',
22+ `account_id` int NOT NULL DEFAULT '0',
23+ `level` int NOT NULL DEFAULT '1',
24+ `vocation` int NOT NULL DEFAULT '0',
25+ `health` int NOT NULL DEFAULT '150',
26+ `healthmax` int NOT NULL DEFAULT '150',
27+ `experience` bigint unsigned NOT NULL DEFAULT '0',
28+ `lookbody` int NOT NULL DEFAULT '0',
29+ `lookfeet` int NOT NULL DEFAULT '0',
30+ `lookhead` int NOT NULL DEFAULT '0',
31+ `looklegs` int NOT NULL DEFAULT '0',
32+ `looktype` int NOT NULL DEFAULT '136',
33+ `lookaddons` int NOT NULL DEFAULT '0',
34+ `lookmount` int NOT NULL DEFAULT '0',
35+ `lookmounthead` int NOT NULL DEFAULT '0',
36+ `lookmountbody` int NOT NULL DEFAULT '0',
37+ `lookmountlegs` int NOT NULL DEFAULT '0',
38+ `lookmountfeet` int NOT NULL DEFAULT '0',
39+ `currentmount` smallint unsigned NOT NULL DEFAULT '0',
40+ `randomizemount` tinyint NOT NULL DEFAULT '0',
41+ `direction` tinyint unsigned NOT NULL DEFAULT '2',
42+ `maglevel` int NOT NULL DEFAULT '0',
43+ `mana` int NOT NULL DEFAULT '0',
44+ `manamax` int NOT NULL DEFAULT '0',
45+ `manaspent` bigint unsigned NOT NULL DEFAULT '0',
46+ `soul` int unsigned NOT NULL DEFAULT '0',
47+ `town_id` int NOT NULL DEFAULT '1',
48+ `posx` int NOT NULL DEFAULT '0',
49+ `posy` int NOT NULL DEFAULT '0',
50+ `posz` int NOT NULL DEFAULT '0',
51+ `conditions` blob DEFAULT NULL,
52+ `cap` int NOT NULL DEFAULT '400',
53+ `sex` int NOT NULL DEFAULT '0',
54+ `lastlogin` bigint unsigned NOT NULL DEFAULT '0',
55+ `lastip` varbinary(16) NOT NULL DEFAULT '0',
56+ `save` tinyint NOT NULL DEFAULT '1',
57+ `skull` tinyint NOT NULL DEFAULT '0',
58+ `skulltime` bigint NOT NULL DEFAULT '0',
59+ `lastlogout` bigint unsigned NOT NULL DEFAULT '0',
60+ `blessings` tinyint NOT NULL DEFAULT '0',
61+ `onlinetime` bigint NOT NULL DEFAULT '0',
62+ `deletion` bigint NOT NULL DEFAULT '0',
63+ `balance` bigint unsigned NOT NULL DEFAULT '0',
64+ `offlinetraining_time` smallint unsigned NOT NULL DEFAULT '43200',
65+ `offlinetraining_skill` int NOT NULL DEFAULT '-1',
66+ `stamina` smallint unsigned NOT NULL DEFAULT '2520',
67+ `skill_fist` int unsigned NOT NULL DEFAULT 10,
68+ `skill_fist_tries` bigint unsigned NOT NULL DEFAULT 0,
69+ `skill_club` int unsigned NOT NULL DEFAULT 10,
70+ `skill_club_tries` bigint unsigned NOT NULL DEFAULT 0,
71+ `skill_sword` int unsigned NOT NULL DEFAULT 10,
72+ `skill_sword_tries` bigint unsigned NOT NULL DEFAULT 0,
73+ `skill_axe` int unsigned NOT NULL DEFAULT 10,
74+ `skill_axe_tries` bigint unsigned NOT NULL DEFAULT 0,
75+ `skill_dist` int unsigned NOT NULL DEFAULT 10,
76+ `skill_dist_tries` bigint unsigned NOT NULL DEFAULT 0,
77+ `skill_shielding` int unsigned NOT NULL DEFAULT 10,
78+ `skill_shielding_tries` bigint unsigned NOT NULL DEFAULT 0,
79+ `skill_fishing` int unsigned NOT NULL DEFAULT 10,
80+ `skill_fishing_tries` bigint unsigned NOT NULL DEFAULT 0,
81+ PRIMARY KEY (`id`),
82+ UNIQUE KEY `name` (`name`),
83+ FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
84+ KEY `vocation` (`vocation`)
85+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
86+
87+CREATE TABLE IF NOT EXISTS `account_bans` (
88+ `account_id` int NOT NULL,
89+ `reason` varchar(255) NOT NULL,
90+ `banned_at` bigint NOT NULL,
91+ `expires_at` bigint NOT NULL,
92+ `banned_by` int NOT NULL,
93+ PRIMARY KEY (`account_id`),
94+ FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
95+ FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
96+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
97+
98+CREATE TABLE IF NOT EXISTS `account_ban_history` (
99+ `id` int unsigned NOT NULL AUTO_INCREMENT,
100+ `account_id` int NOT NULL,
101+ `reason` varchar(255) NOT NULL,
102+ `banned_at` bigint NOT NULL,
103+ `expired_at` bigint NOT NULL,
104+ `banned_by` int NOT NULL,
105+ PRIMARY KEY (`id`),
106+ FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
107+ FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
108+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
109+
110+CREATE TABLE IF NOT EXISTS `account_storage` (
111+ `account_id` int NOT NULL,
112+ `key` int unsigned NOT NULL,
113+ `value` int NOT NULL,
114+ PRIMARY KEY (`account_id`, `key`),
115+ FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE CASCADE
116+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
117+
118+CREATE TABLE IF NOT EXISTS `ip_bans` (
119+ `ip` varbinary(16) NOT NULL,
120+ `reason` varchar(255) NOT NULL,
121+ `banned_at` bigint NOT NULL,
122+ `expires_at` bigint NOT NULL,
123+ `banned_by` int NOT NULL,
124+ PRIMARY KEY (`ip`),
125+ FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
126+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
127+
128+CREATE TABLE IF NOT EXISTS `player_namelocks` (
129+ `player_id` int NOT NULL,
130+ `reason` varchar(255) NOT NULL,
131+ `namelocked_at` bigint NOT NULL,
132+ `namelocked_by` int NOT NULL,
133+ PRIMARY KEY (`player_id`),
134+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
135+ FOREIGN KEY (`namelocked_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
136+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
137+
138+CREATE TABLE IF NOT EXISTS `account_viplist` (
139+ `account_id` int NOT NULL COMMENT 'id of account whose viplist entry it is',
140+ `player_id` int NOT NULL COMMENT 'id of target player of viplist entry',
141+ `description` varchar(128) NOT NULL DEFAULT '',
142+ `icon` tinyint unsigned NOT NULL DEFAULT '0',
143+ `notify` tinyint NOT NULL DEFAULT '0',
144+ UNIQUE KEY `account_player_index` (`account_id`,`player_id`),
145+ FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
146+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE
147+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
148+
149+CREATE TABLE IF NOT EXISTS `guilds` (
150+ `id` int NOT NULL AUTO_INCREMENT,
151+ `name` varchar(255) NOT NULL,
152+ `ownerid` int NOT NULL,
153+ `creationdata` int NOT NULL,
154+ `motd` varchar(255) NOT NULL DEFAULT '',
155+ PRIMARY KEY (`id`),
156+ UNIQUE KEY (`name`),
157+ UNIQUE KEY (`ownerid`),
158+ FOREIGN KEY (`ownerid`) REFERENCES `players`(`id`) ON DELETE CASCADE
159+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
160+
161+CREATE TABLE IF NOT EXISTS `guild_invites` (
162+ `player_id` int NOT NULL DEFAULT '0',
163+ `guild_id` int NOT NULL DEFAULT '0',
164+ PRIMARY KEY (`player_id`,`guild_id`),
165+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE,
166+ FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE
167+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
168+
169+CREATE TABLE IF NOT EXISTS `guild_ranks` (
170+ `id` int NOT NULL AUTO_INCREMENT,
171+ `guild_id` int NOT NULL COMMENT 'guild',
172+ `name` varchar(255) NOT NULL COMMENT 'rank name',
173+ `level` int NOT NULL COMMENT 'rank level - leader, vice, member, maybe something else',
174+ PRIMARY KEY (`id`),
175+ FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE
176+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
177+
178+CREATE TABLE IF NOT EXISTS `guild_membership` (
179+ `player_id` int NOT NULL,
180+ `guild_id` int NOT NULL,
181+ `rank_id` int NOT NULL,
182+ `nick` varchar(15) NOT NULL DEFAULT '',
183+ PRIMARY KEY (`player_id`),
184+ FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
185+ FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
186+ FOREIGN KEY (`rank_id`) REFERENCES `guild_ranks` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
187+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
188+
189+CREATE TABLE IF NOT EXISTS `guild_wars` (
190+ `id` int NOT NULL AUTO_INCREMENT,
191+ `guild1` int NOT NULL DEFAULT '0',
192+ `guild2` int NOT NULL DEFAULT '0',
193+ `name1` varchar(255) NOT NULL,
194+ `name2` varchar(255) NOT NULL,
195+ `status` tinyint NOT NULL DEFAULT '0',
196+ `started` bigint NOT NULL DEFAULT '0',
197+ `ended` bigint NOT NULL DEFAULT '0',
198+ PRIMARY KEY (`id`),
199+ KEY `guild1` (`guild1`),
200+ KEY `guild2` (`guild2`)
201+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
202+
203+CREATE TABLE IF NOT EXISTS `guildwar_kills` (
204+ `id` int NOT NULL AUTO_INCREMENT,
205+ `killer` varchar(50) NOT NULL,
206+ `target` varchar(50) NOT NULL,
207+ `killerguild` int NOT NULL DEFAULT '0',
208+ `targetguild` int NOT NULL DEFAULT '0',
209+ `warid` int NOT NULL DEFAULT '0',
210+ `time` bigint NOT NULL,
211+ PRIMARY KEY (`id`),
212+ FOREIGN KEY (`warid`) REFERENCES `guild_wars` (`id`) ON DELETE CASCADE
213+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
214+
215+CREATE TABLE IF NOT EXISTS `houses` (
216+ `id` int NOT NULL AUTO_INCREMENT,
217+ `owner` int NOT NULL,
218+ `paid` int unsigned NOT NULL DEFAULT '0',
219+ `warnings` int NOT NULL DEFAULT '0',
220+ `name` varchar(255) NOT NULL,
221+ `rent` int NOT NULL DEFAULT '0',
222+ `town_id` int NOT NULL DEFAULT '0',
223+ `bid` int NOT NULL DEFAULT '0',
224+ `bid_end` int NOT NULL DEFAULT '0',
225+ `last_bid` int NOT NULL DEFAULT '0',
226+ `highest_bidder` int NOT NULL DEFAULT '0',
227+ `size` int NOT NULL DEFAULT '0',
228+ `beds` int NOT NULL DEFAULT '0',
229+ PRIMARY KEY (`id`),
230+ KEY `owner` (`owner`),
231+ KEY `town_id` (`town_id`)
232+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
233+
234+CREATE TABLE IF NOT EXISTS `house_lists` (
235+ `house_id` int NOT NULL,
236+ `listid` int NOT NULL,
237+ `list` text NOT NULL,
238+ FOREIGN KEY (`house_id`) REFERENCES `houses` (`id`) ON DELETE CASCADE
239+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
240+
241+CREATE TABLE IF NOT EXISTS `market_history` (
242+ `id` int unsigned NOT NULL AUTO_INCREMENT,
243+ `player_id` int NOT NULL,
244+ `sale` tinyint NOT NULL DEFAULT '0',
245+ `itemtype` smallint unsigned NOT NULL,
246+ `amount` smallint unsigned NOT NULL,
247+ `price` bigint unsigned NOT NULL DEFAULT '0',
248+ `expires_at` bigint unsigned NOT NULL,
249+ `inserted` bigint unsigned NOT NULL,
250+ `state` tinyint unsigned NOT NULL,
251+ PRIMARY KEY (`id`),
252+ KEY `player_id` (`player_id`, `sale`),
253+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
254+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
255+
256+CREATE TABLE IF NOT EXISTS `market_offers` (
257+ `id` int unsigned NOT NULL AUTO_INCREMENT,
258+ `player_id` int NOT NULL,
259+ `sale` tinyint NOT NULL DEFAULT '0',
260+ `itemtype` smallint unsigned NOT NULL,
261+ `amount` smallint unsigned NOT NULL,
262+ `created` bigint unsigned NOT NULL,
263+ `anonymous` tinyint NOT NULL DEFAULT '0',
264+ `price` bigint unsigned NOT NULL DEFAULT '0',
265+ PRIMARY KEY (`id`),
266+ KEY `sale` (`sale`,`itemtype`),
267+ KEY `created` (`created`),
268+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
269+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
270+
271+CREATE TABLE IF NOT EXISTS `players_online` (
272+ `player_id` int NOT NULL,
273+ PRIMARY KEY (`player_id`)
274+) ENGINE=MEMORY DEFAULT CHARACTER SET=utf8;
275+
276+CREATE TABLE IF NOT EXISTS `player_deaths` (
277+ `player_id` int NOT NULL,
278+ `time` bigint unsigned NOT NULL DEFAULT '0',
279+ `level` int NOT NULL DEFAULT '1',
280+ `killed_by` varchar(255) NOT NULL,
281+ `is_player` tinyint NOT NULL DEFAULT '1',
282+ `mostdamage_by` varchar(100) NOT NULL,
283+ `mostdamage_is_player` tinyint NOT NULL DEFAULT '0',
284+ `unjustified` tinyint NOT NULL DEFAULT '0',
285+ `mostdamage_unjustified` tinyint NOT NULL DEFAULT '0',
286+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE,
287+ KEY `killed_by` (`killed_by`),
288+ KEY `mostdamage_by` (`mostdamage_by`)
289+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
290+
291+CREATE TABLE IF NOT EXISTS `player_depotitems` (
292+ `player_id` int NOT NULL,
293+ `sid` int NOT NULL COMMENT 'any given range eg 0-100 will be reserved for depot lockers and all > 100 will be then normal items inside depots',
294+ `pid` int NOT NULL DEFAULT '0',
295+ `itemtype` smallint unsigned NOT NULL,
296+ `count` smallint NOT NULL DEFAULT '0',
297+ `attributes` blob NOT NULL,
298+ UNIQUE KEY `player_id_2` (`player_id`, `sid`),
299+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
300+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
301+
302+CREATE TABLE IF NOT EXISTS `player_inboxitems` (
303+ `player_id` int NOT NULL,
304+ `sid` int NOT NULL,
305+ `pid` int NOT NULL DEFAULT '0',
306+ `itemtype` smallint unsigned NOT NULL,
307+ `count` smallint NOT NULL DEFAULT '0',
308+ `attributes` blob NOT NULL,
309+ UNIQUE KEY `player_id_2` (`player_id`, `sid`),
310+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
311+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
312+
313+CREATE TABLE IF NOT EXISTS `player_storeinboxitems` (
314+ `player_id` int NOT NULL,
315+ `sid` int NOT NULL,
316+ `pid` int NOT NULL DEFAULT '0',
317+ `itemtype` smallint unsigned NOT NULL,
318+ `count` smallint NOT NULL DEFAULT '0',
319+ `attributes` blob NOT NULL,
320+ UNIQUE KEY `player_id_2` (`player_id`, `sid`),
321+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
322+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
323+
324+CREATE TABLE IF NOT EXISTS `player_items` (
325+ `player_id` int NOT NULL DEFAULT '0',
326+ `pid` int NOT NULL DEFAULT '0',
327+ `sid` int NOT NULL DEFAULT '0',
328+ `itemtype` smallint unsigned NOT NULL DEFAULT '0',
329+ `count` smallint NOT NULL DEFAULT '0',
330+ `attributes` blob NOT NULL,
331+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE,
332+ KEY `sid` (`sid`)
333+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
334+
335+CREATE TABLE IF NOT EXISTS `player_spells` (
336+ `player_id` int NOT NULL,
337+ `name` varchar(255) NOT NULL,
338+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
339+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
340+
341+CREATE TABLE IF NOT EXISTS `player_storage` (
342+ `player_id` int NOT NULL DEFAULT '0',
343+ `key` int unsigned NOT NULL DEFAULT '0',
344+ `value` int NOT NULL DEFAULT '0',
345+ PRIMARY KEY (`player_id`,`key`),
346+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
347+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
348+
349+CREATE TABLE IF NOT EXISTS `player_outfits` (
350+ `player_id` int NOT NULL DEFAULT '0',
351+ `outfit_id` smallint unsigned NOT NULL DEFAULT '0',
352+ `addons` tinyint unsigned NOT NULL DEFAULT '0',
353+ PRIMARY KEY (`player_id`,`outfit_id`),
354+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
355+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
356+
357+CREATE TABLE IF NOT EXISTS `player_mounts` (
358+ `player_id` int NOT NULL DEFAULT '0',
359+ `mount_id` smallint unsigned NOT NULL DEFAULT '0',
360+ PRIMARY KEY (`player_id`,`mount_id`),
361+ FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
362+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
363+
364+CREATE TABLE IF NOT EXISTS `server_config` (
365+ `config` varchar(50) NOT NULL,
366+ `value` varchar(256) NOT NULL DEFAULT '',
367+ PRIMARY KEY `config` (`config`)
368+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
369+
370+CREATE TABLE IF NOT EXISTS `sessions` (
371+ `id` int NOT NULL AUTO_INCREMENT,
372+ `token` binary(16) NOT NULL,
373+ `account_id` int NOT NULL,
374+ `ip` varbinary(16) NOT NULL,
375+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
376+ `expired_at` timestamp,
377+ PRIMARY KEY (`id`),
378+ UNIQUE KEY `token` (`token`),
379+ FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE
380+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
381+
382+CREATE TABLE IF NOT EXISTS `tile_store` (
383+ `house_id` int NOT NULL,
384+ `data` longblob NOT NULL,
385+ FOREIGN KEY (`house_id`) REFERENCES `houses` (`id`) ON DELETE CASCADE
386+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
387+
388+CREATE TABLE IF NOT EXISTS `towns` (
389+ `id` int NOT NULL AUTO_INCREMENT,
390+ `name` varchar(255) NOT NULL,
391+ `posx` int NOT NULL DEFAULT '0',
392+ `posy` int NOT NULL DEFAULT '0',
393+ `posz` int NOT NULL DEFAULT '0',
394+ PRIMARY KEY (`id`),
395+ UNIQUE KEY `name` (`name`)
396+) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
397+
398+INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '37'), ('players_record', '0');
399+
400+DROP TRIGGER IF EXISTS `ondelete_players`;
401+DROP TRIGGER IF EXISTS `oncreate_guilds`;
402+
403+DELIMITER //
404+CREATE TRIGGER `ondelete_players` BEFORE DELETE ON `players`
405+ FOR EACH ROW BEGIN
406+ UPDATE `houses` SET `owner` = 0 WHERE `owner` = OLD.`id`;
407+END
408+//
409+CREATE TRIGGER `oncreate_guilds` AFTER INSERT ON `guilds`
410+ FOR EACH ROW BEGIN
411+ INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('the Leader', 3, NEW.`id`);
412+ INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('a Vice-Leader', 2, NEW.`id`);
413+ INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('a Member', 1, NEW.`id`);
414+END
415+//
416+DELIMITER ;
A docker/php.ini +16-0 View file
@@ -0,0 +1,16 @@
1+memory_limit = 256M
2+upload_max_filesize = 20M
3+post_max_size = 20M
4+max_execution_time = 60
5+date.timezone = UTC
6+
7+display_errors = Off
8+log_errors = On
9+error_log = /dev/stderr
10+
11+opcache.enable = 1
12+opcache.memory_consumption = 128
13+opcache.validate_timestamps = 1
14+opcache.revalidate_freq = 1
15+
16+apc.enable_cli = 0
A Dockerfile +36-0 View file
@@ -0,0 +1,36 @@
1+FROM php:8.5-apache
2+
3+RUN apt-get update && apt-get install -y --no-install-recommends \
4+ libzip-dev \
5+ libpng-dev \
6+ libjpeg62-turbo-dev \
7+ libfreetype6-dev \
8+ libcurl4-openssl-dev \
9+ libonig-dev \
10+ unzip \
11+ git \
12+ && docker-php-ext-configure gd --with-jpeg --with-freetype \
13+ && docker-php-ext-install mysqli pdo_mysql zip gd curl \
14+ && pecl install apcu \
15+ && docker-php-ext-enable apcu \
16+ && a2enmod rewrite \
17+ && apt-get purge -y --auto-remove git \
18+ && rm -rf /var/lib/apt/lists/*
19+
20+COPY docker/php.ini /usr/local/etc/php/conf.d/znotex.ini
21+COPY docker/apache-htaccess.conf /etc/apache2/conf-enabled/z-znotex.conf
22+
23+COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
24+
25+WORKDIR /var/www/html
26+
27+COPY . .
28+RUN composer install --no-dev --no-interaction --no-scripts --optimize-autoloader \
29+ && chown -R www-data:www-data /var/www/html \
30+ && chmod -R u+rwX,g+rX engine/cache engine/img/theme 2>/dev/null || true
31+
32+COPY docker/entrypoint.sh /usr/local/bin/znotex-entrypoint.sh
33+RUN chmod +x /usr/local/bin/znotex-entrypoint.sh
34+
35+ENTRYPOINT ["/usr/local/bin/znotex-entrypoint.sh"]
36+CMD ["apache2-foreground"]
A downloads.php +5-0 View file
@@ -0,0 +1,5 @@
1+<?php require_once 'engine/init.php'; theme_open();
2+
3+view('downloads');
4+
5+theme_close();
A engine/adapter/BlackTekAdapter.php +40-0 View file
@@ -0,0 +1,40 @@
1+<?php
2+/**
3+ * BlackTek (https://github.com/Black-Tek/BlackTek-Server): a TFS fork whose
4+ * schema.sql - checked against its `master` branch - matches TFS_10 in every
5+ * way that matters here: `accounts` has `name` and a `secret` char(16) column,
6+ * `players_online` exists, `houses` uses the TFS column names (not Canary's
7+ * renamed internal_bid/bid_end_date/...), and both `guild_membership` and
8+ * `guild_ranks` exist. So it is normalised to TFS_10 for querying (see
9+ * engine/init.php) and the legacy accounts.secret 2FA flow works unmodified.
10+ */
11+final class BlackTekAdapter implements ServerAdapterInterface
12+{
13+ public function key(): string {
14+ return 'BLACKTEK';
15+ }
16+
17+ public function login(string $username, string $password): int|false {
18+ return user_login($username, $password);
19+ }
20+
21+ public function accountIdentityColumn(): string {
22+ return 'name';
23+ }
24+
25+ public function accountDisplayColumn(): string {
26+ return '`a`.`name`';
27+ }
28+
29+ public function supportsLegacyTwoFactor(): bool {
30+ return true;
31+ }
32+
33+ public function onlineCount(): int {
34+ return znote_sql_count("SELECT COUNT(*) AS `c` FROM `players_online`;");
35+ }
36+
37+ public function normalizedEngine(): string {
38+ return 'TFS_10';
39+ }
40+}
A engine/adapter/CanaryAdapter.php +36-0 View file
@@ -0,0 +1,36 @@
1+<?php
2+/**
3+ * Canary. Normalised to the TFS_10 schema for querying (see engine/init.php),
4+ * but it is not TFS: the legacy accounts.secret 2FA flow does not apply, which
5+ * is why engine/init.php also forces twoFactorAuthenticator off for it.
6+ */
7+final class CanaryAdapter implements ServerAdapterInterface
8+{
9+ public function key(): string {
10+ return 'CANARY';
11+ }
12+
13+ public function login(string $username, string $password): int|false {
14+ return user_login($username, $password);
15+ }
16+
17+ public function accountIdentityColumn(): string {
18+ return 'name';
19+ }
20+
21+ public function accountDisplayColumn(): string {
22+ return '`a`.`name`';
23+ }
24+
25+ public function supportsLegacyTwoFactor(): bool {
26+ return false;
27+ }
28+
29+ public function onlineCount(): int {
30+ return znote_sql_count("SELECT COUNT(*) AS `c` FROM `players_online`;");
31+ }
32+
33+ public function normalizedEngine(): string {
34+ return 'TFS_10';
35+ }
36+}
A engine/adapter/factory.php +21-0 View file
@@ -0,0 +1,21 @@
1+<?php
2+
3+function znote_server_adapter(?string $engine = null): ServerAdapterInterface {
4+ static $cache = array();
5+
6+ global $config;
7+ $engine = $engine ?? (string)($config['ServerEngineReal'] ?? $config['ServerEngine'] ?? 'TFS_10');
8+
9+ if (isset($cache[$engine])) {
10+ return $cache[$engine];
11+ }
12+
13+ $adapter = match ($engine) {
14+ 'OTHIRE' => new OtHireAdapter(),
15+ 'CANARY' => new CanaryAdapter(),
16+ 'BLACKTEK' => new BlackTekAdapter(),
17+ default => new TFSAdapter($engine), // TFS_02, TFS_03, TFS_10, TFS_16
18+ };
19+
20+ return $cache[$engine] = $adapter;
21+}
A engine/adapter/OtHireAdapter.php +35-0 View file
@@ -0,0 +1,35 @@
1+<?php
2+/**
3+ * otHire: accounts have no `name` column, an account is identified by its
4+ * numeric id everywhere a TFS-based engine would use a name.
5+ */
6+final class OtHireAdapter implements ServerAdapterInterface
7+{
8+ public function key(): string {
9+ return 'OTHIRE';
10+ }
11+
12+ public function login(string $username, string $password): int|false {
13+ return user_login($username, $password);
14+ }
15+
16+ public function accountIdentityColumn(): string {
17+ return 'id';
18+ }
19+
20+ public function accountDisplayColumn(): string {
21+ return '`a`.`id`';
22+ }
23+
24+ public function supportsLegacyTwoFactor(): bool {
25+ return false;
26+ }
27+
28+ public function onlineCount(): int {
29+ return znote_sql_count("SELECT COUNT(*) AS `c` FROM `players` WHERE `online` > 0;");
30+ }
31+
32+ public function normalizedEngine(): string {
33+ return 'OTHIRE';
34+ }
35+}
A engine/adapter/ServerAdapterInterface.php +58-0 View file
@@ -0,0 +1,58 @@
1+<?php
2+/**
3+ * Server Adapter.
4+ *
5+ * Every place that used to branch on $config['ServerEngine'] directly is a
6+ * place that has to be found and re-checked whenever a new engine shows up.
7+ * This interface collects the differences that actually matter to the
8+ * website - how an account logs in, how it is identified, whether the legacy
9+ * in-game 2FA exists, how "online" is counted - behind one call:
10+ * znote_server_adapter().
11+ *
12+ * This does not replace every scattered ServerEngine check in one pass - that
13+ * would be the highest-risk change in the codebase, done all at once, with no
14+ * way to review it in reviewable pieces. It gives new code, and code being
15+ * touched anyway, somewhere better to live. login.php and the admin
16+ * dashboard/analytics modules are wired to it as the first, carefully tested
17+ * examples; the rest can move over one file at a time.
18+ */
19+
20+/** COUNT(*) helper shared by the adapters - 0 for a table this engine does not have. */
21+function znote_sql_count(string $sql, array $params = array()): int {
22+ $row = db()->fetchOne($sql, $params);
23+ return is_array($row) && $row ? (int)reset($row) : 0;
24+}
25+
26+interface ServerAdapterInterface
27+{
28+ /** The ServerEngineReal value this adapter was built for. */
29+ public function key(): string;
30+
31+ /**
32+ * Authenticates a username/password pair against `accounts`.
33+ * Returns the account id, or false.
34+ */
35+ public function login(string $username, string $password): int|false;
36+
37+ /** The `accounts` column identity is checked against - 'name' everywhere except otHire. */
38+ public function accountIdentityColumn(): string;
39+
40+ /** SQL fragment for a human-readable account label in a query - `a`.`name` or `a`.`id`. */
41+ public function accountDisplayColumn(): string;
42+
43+ /** Whether the legacy, engine-tied 2FA (accounts.secret, twofa.php) can work here. */
44+ public function supportsLegacyTwoFactor(): bool;
45+
46+ /** How many characters are online right now. */
47+ public function onlineCount(): int;
48+
49+ /**
50+ * The engine value the rest of the codebase should dispatch on for schema
51+ * differences: one of 'TFS_02', 'TFS_03', 'TFS_10' or 'OTHIRE'. Canary,
52+ * TFS_16 and BlackTek all report 'TFS_10' here - they already run that
53+ * schema, which is exactly what $config['ServerEngine'] was normalised to
54+ * in engine/init.php. This is the single place that mapping lives now,
55+ * instead of every file re-deriving it.
56+ */
57+ public function normalizedEngine(): string;
58+}
A engine/adapter/TFSAdapter.php +46-0 View file
@@ -0,0 +1,46 @@
1+<?php
2+/**
3+ * TFS_02, TFS_03, TFS_10 and TFS_16 (TFS_16 already runs the TFS_10 schema,
4+ * normalised in engine/init.php). TFS_03's salted password scheme is the one
5+ * real behavioural difference among them.
6+ */
7+final class TFSAdapter implements ServerAdapterInterface
8+{
9+ public function __construct(private string $realEngine) {
10+ }
11+
12+ public function key(): string {
13+ return $this->realEngine;
14+ }
15+
16+ public function login(string $username, string $password): int|false {
17+ if ($this->realEngine === 'TFS_03') {
18+ return user_login_03($username, $password);
19+ }
20+ return user_login($username, $password);
21+ }
22+
23+ public function accountIdentityColumn(): string {
24+ return 'name';
25+ }
26+
27+ public function accountDisplayColumn(): string {
28+ return '`a`.`name`';
29+ }
30+
31+ public function supportsLegacyTwoFactor(): bool {
32+ // accounts.secret and the QR-code flow in twofa.php only exist from TFS 1.2.
33+ return $this->realEngine === 'TFS_10';
34+ }
35+
36+ public function onlineCount(): int {
37+ return $this->realEngine === 'TFS_10'
38+ ? znote_sql_count("SELECT COUNT(*) AS `c` FROM `players_online`;")
39+ : znote_sql_count("SELECT COUNT(*) AS `c` FROM `players` WHERE `online` > 0;");
40+ }
41+
42+ public function normalizedEngine(): string {
43+ // TFS_16 already runs the TFS_10 schema (normalised in engine/init.php).
44+ return $this->realEngine === 'TFS_16' ? 'TFS_10' : $this->realEngine;
45+ }
46+}
Top