fix errors on insertion to game, fix db creation of game

This commit is contained in:
lbenedar
2026-04-23 19:03:56 +03:00
parent f46ff8333e
commit 07025afefc
36 changed files with 1820 additions and 693 deletions

View File

@@ -19,6 +19,7 @@ DROP TABLE IF EXISTS system;
DROP TABLE IF EXISTS package_warnings_data_error;
DROP TABLE IF EXISTS package_warnings_data_warning;
DROP TABLE IF EXISTS package_warnings_data;
DROP TRIGGER IF EXISTS tr_delete_package_warnings_to_data_package_warnings_data;
DROP TABLE IF EXISTS package_warnings;
DROP TABLE IF EXISTS news;
DROP TABLE IF EXISTS folder_packs;

View File

@@ -397,15 +397,30 @@ CREATE TABLE IF NOT EXISTS package_warnings (
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS package_warnings_to_data (
package_warnings_id INTEGER,
package_warnings_data_id TEXT,
PRIMARY KEY (package_warnings_id, package_warnings_data_id),
FOREIGN KEY (package_warnings_id) REFERENCES package_warnings(id) ON DELETE CASCADE,
FOREIGN KEY (package_warnings_data_id) REFERENCES package_warnings_data(id) ON DELETE CASCADE
);
CREATE TRIGGER tr_delete_package_warnings_to_data_package_warnings_data
AFTER DELETE ON package_warnings_to_data
FOR EACH ROW
BEGIN
DELETE FROM package_warnings_data
WHERE id = OLD.id
AND NOT EXISTS (SELECT 1 FROM package_warnings_to_data WHERE package_warnings_data_id = OLD.package_warnings_data_id);
END;
CREATE TABLE IF NOT EXISTS package_warnings_data (
id TEXT PRIMARY KEY,
type VARCHAR(128) NOT NULL,
manifest VARCHAR(128) NOT NULL,
reinstallable BOOLEAN NOT NULL,
package_warnings_id INTEGER,
FOREIGN KEY (package_warnings_id) REFERENCES package_warnings(id) ON DELETE CASCADE
reinstallable BOOLEAN NOT NULL
);
CREATE TABLE IF NOT EXISTS package_warnings_data_warning (
@@ -510,6 +525,9 @@ CREATE TABLE IF NOT EXISTS world (
owned BOOLEAN NOT NULL DEFAULT FALSE,
has_storage BOOLEAN NOT NULL DEFAULT FALSE,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now')),
setup_id INTEGER,
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
);

View File

@@ -1,3 +1,191 @@
DROP TABLE IF EXISTS modules_languages;
DROP TABLE IF EXISTS modules_compatibility;
DROP TABLE IF EXISTS modules;
DROP TRIGGER IF EXISTS tr_delete_package_warnings_to_data_package_warnings_data;
DROP TRIGGER IF EXISTS tr_delete_game_to_systems_system;
DROP TRIGGER IF EXISTS tr_delete_game_to_module_module;
DROP TABLE IF EXISTS token_turn_maker;
DROP TABLE IF EXISTS token_occludable;
DROP TABLE IF EXISTS token_light_darkness;
DROP TABLE IF EXISTS token_light_animation;
DROP TABLE IF EXISTS token_light;
DROP TABLE IF EXISTS token_bar_2;
DROP TABLE IF EXISTS token_bar_1;
DROP TABLE IF EXISTS token_texture;
DROP TABLE IF EXISTS token_sight;
DROP TABLE IF EXISTS ring_subject;
DROP TABLE IF EXISTS ring_colors;
DROP TABLE IF EXISTS ring;
DROP TABLE IF EXISTS token;
DROP TABLE IF EXISTS actor;
DROP TABLE IF EXISTS sound;
DROP TABLE IF EXISTS playlist;
DROP TABLE IF EXISTS table_result_range;
DROP TABLE IF EXISTS table_result;
DROP TABLE IF EXISTS table_;
DROP TABLE IF EXISTS journal_page_video;
DROP TABLE IF EXISTS journal_page_title;
DROP TABLE IF EXISTS journal_page_text;
DROP TABLE IF EXISTS journal_page;
DROP TABLE IF EXISTS journal;
DROP TABLE IF EXISTS setting;
DROP TABLE IF EXISTS item;
DROP TABLE IF EXISTS world_folder;
DROP TABLE IF EXISTS macro;
DROP TABLE IF EXISTS hotbar;
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS face;
DROP TABLE IF EXISTS back;
DROP TABLE IF EXISTS card;
DROP TABLE IF EXISTS ownership_string;
DROP TABLE IF EXISTS card_deck;
DROP TABLE IF EXISTS combatant;
DROP TABLE IF EXISTS combat_groups;
DROP TABLE IF EXISTS combat;
DROP TABLE IF EXISTS message_rolls;
DROP TABLE IF EXISTS message_whisper;
DROP TABLE IF EXISTS speaker;
DROP TABLE IF EXISTS stats;
DROP TABLE IF EXISTS message;
CREATE TABLE IF NOT EXISTS pack_new (
id INTEGER PRIMARY KEY,
key_ VARCHAR(128) NOT NULL,
name VARCHAR(128) NOT NULL,
label VARCHAR(128) NOT NULL,
banner VARCHAR(128) NOT NULL,
path VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
system VARCHAR(128) NOT NULL,
package_type VARCHAR(128) NOT NULL,
package_name VARCHAR(128) NOT NULL,
module_id TEXT,
FOREIGN KEY (module_id) REFERENCES module(id) ON DELETE CASCADE
);
ALTER TABLE pack_new ADD COLUMN system_id TEXT REFERENCES system(id) ON DELETE CASCADE;
ALTER TABLE pack_new ADD COLUMN world_id TEXT REFERENCES world(id) ON DELETE CASCADE;
INSERT INTO pack_new (id, key_, name, label, banner, path, type, system, package_type, package_name, module_id, system_id, world_id)
SELECT id, key_, name, label, banner, path, type, system, package_type, package_name, module_id, system_id, world_id FROM pack;
DROP TABLE IF EXISTS pack;
ALTER TABLE pack_new RENAME TO pack;
CREATE TABLE IF NOT EXISTS package_warnings_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key_ TEXT NOT NULL,
setup_id INTEGER,
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
);
INSERT INTO package_warnings_new (id, key_, setup_id)
SELECT id, key_, setup_id FROM package_warnings;
DROP TABLE IF EXISTS package_warnings;
ALTER TABLE package_warnings_new RENAME TO package_warnings;
DROP TABLE IF EXISTS active_users;
DROP TABLE IF EXISTS system_update;
DROP INDEX IF EXISTS idx_core_update_game_id;
CREATE TABLE IF NOT EXISTS core_update_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
has_update BOOLEAN NOT NULL DEFAULT FALSE,
can_update BOOLEAN NOT NULL DEFAULT FALSE,
could_reach_website BOOLEAN NOT NULL DEFAULT FALSE,
slow_response BOOLEAN NOT NULL DEFAULT FALSE,
will_disable_modules BOOLEAN NOT NULL DEFAULT FALSE,
version VARCHAR(64) NOT NULL,
channel VARCHAR(64) NOT NULL,
setup_id INTEGER UNIQUE,
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
);
INSERT INTO core_update_new (id, has_update, can_update, could_reach_website, slow_response, will_disable_modules, version, channel, setup_id)
SELECT id, has_update, can_update, could_reach_website, slow_response, will_disable_modules, version, channel, setup_id FROM core_update;
DROP TABLE IF EXISTS core_update;
ALTER TABLE core_update_new RENAME TO core_update;
DROP TABLE IF EXISTS game_to_systems;
DROP INDEX IF EXISTS idx_world_game_id;
CREATE TABLE IF NOT EXISTS world_new (
id TEXT PRIMARY KEY,
title VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
version VARCHAR(128) NOT NULL,
system VARCHAR(128) NOT NULL,
background VARCHAR(128) NOT NULL,
join_theme VARCHAR(128) NOT NULL,
core_version VARCHAR(128) NOT NULL,
system_version VARCHAR(128) NOT NULL,
last_played VARCHAR(128) NOT NULL,
playtime INTEGER NOT NULL,
availability INTEGER NOT NULL,
next_session DATETIME NOT NULL,
socket BOOLEAN NOT NULL DEFAULT FALSE,
protected BOOLEAN NOT NULL DEFAULT FALSE,
exclusive_ BOOLEAN NOT NULL DEFAULT FALSE,
persistent_storage BOOLEAN NOT NULL DEFAULT FALSE,
locked BOOLEAN NOT NULL DEFAULT FALSE,
owned BOOLEAN NOT NULL DEFAULT FALSE,
has_storage BOOLEAN NOT NULL DEFAULT FALSE,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now')),
setup_id INTEGER,
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
);
INSERT INTO world_new (id, title, description, version, system, background, join_theme, core_version, system_version, last_played, playtime, availability, next_session, socket, protected, exclusive_, persistent_storage, locked, owned, has_storage, created_at, updated_at, setup_id)
SELECT id, title, description, version, system, background, join_theme, core_version, system_version, last_played, playtime, availability, next_session, socket, protected, exclusive_, persistent_storage, locked, owned, has_storage, created_at, updated_at, setup_id FROM world;
DROP TABLE IF EXISTS world;
ALTER TABLE world_new RENAME TO world;
DROP INDEX IF EXISTS idx_release_game_id;
CREATE TABLE IF NOT EXISTS release_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
generation INTEGER NOT NULL,
build INTEGER NOT NULL,
node_version INTEGER NOT NULL,
max_generation INTEGER NOT NULL,
max_stable_generation INTEGER NOT NULL,
time DATETIME NOT NULL,
channel VARCHAR(128) NOT NULL,
suffix VARCHAR(128) NOT NULL,
setup_id INTEGER UNIQUE,
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
);
INSERT INTO release_new (id, generation, build, node_version, max_generation, max_stable_generation, time, channel, suffix, setup_id)
SELECT id, generation, build, node_version, max_generation, max_stable_generation, time, channel, suffix, setup_id FROM release_;
DROP TABLE IF EXISTS release_;
ALTER TABLE release_new RENAME TO release_;
DROP TABLE IF EXISTS game_options;
DROP INDEX IF EXISTS idx_files_game_id;
DROP TABLE IF EXISTS files_new;
CREATE TABLE IF NOT EXISTS files_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
setup_id INTEGER UNIQUE,
FOREIGN KEY (setup_id) REFERENCES setup(id) ON DELETE CASCADE
);
INSERT INTO files_new (id, setup_id)
SELECT id, setup_id FROM files;
DROP TABLE IF EXISTS files;
ALTER TABLE files_new RENAME TO files;
DROP TABLE IF EXISTS addresses;
DROP TABLE IF EXISTS game;
CREATE TRIGGER tr_delete_package_warnings_to_data_package_warnings_data
AFTER DELETE ON package_warnings_to_data
FOR EACH ROW
BEGIN
DELETE FROM package_warnings_data
WHERE id = OLD.id
AND NOT EXISTS (SELECT 1 FROM package_warnings_to_data WHERE package_warnings_data_id = OLD.package_warnings_data_id);
END;

View File

@@ -1,5 +1,5 @@
CREATE TABLE IF NOT EXISTS game (
id INTEGER PRIMARY KEY AUTOINCREMENT
id INTEGER PRIMARY KEY AUTOINCREMENT,
demo_mode BOOLEAN NOT NULL DEFAULT FALSE,
idle_logout BOOLEAN NOT NULL DEFAULT FALSE,
@@ -20,6 +20,8 @@ CREATE TABLE IF NOT EXISTS addresses (
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE files ADD COLUMN game_id INTEGER REFERENCES game(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_files_game_id ON files(game_id);
CREATE TABLE IF NOT EXISTS game_options (
id INTEGER PRIMARY KEY,
@@ -32,22 +34,280 @@ CREATE TABLE IF NOT EXISTS game_options (
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS macro (
id TEXT PRIMARY KEY,
ALTER TABLE release_ ADD COLUMN game_id INTEGER REFERENCES game(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_release_game_id ON release_(game_id);
ALTER TABLE world ADD COLUMN game_id INTEGER REFERENCES game(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_world_game_id ON world(game_id);
command VARCHAR(128) NOT NULL,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
author VARCHAR(128) NOT NULL,
scope VARCHAR(128) NOT NULL,
folder VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
CREATE TABLE IF NOT EXISTS game_to_systems (
game_id INTEGER,
system_id TEXT,
PRIMARY KEY (game_id, system_id),
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE,
FOREIGN KEY (system_id) REFERENCES system(id) ON DELETE CASCADE
);
CREATE TRIGGER tr_delete_game_to_systems_system
AFTER DELETE ON game_to_systems
FOR EACH ROW
BEGIN
DELETE FROM system
WHERE id = OLD.id
AND NOT EXISTS (SELECT 1 FROM game_to_systems WHERE system_id = OLD.system_id);
END;
ALTER TABLE core_update ADD COLUMN game_id INTEGER REFERENCES game(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_core_update_game_id ON core_update(game_id);
CREATE TABLE IF NOT EXISTS system_update (
id INTEGER PRIMARY KEY AUTOINCREMENT,
has_update BOOLEAN NOT NULL DEFAULT FALSE,
version VARCHAR(128) NOT NULL,
game_id INTEGER UNIQUE,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS active_users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
value VARCHAR(128) NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS game_to_module (
game_id INTEGER,
module_id TEXT,
PRIMARY KEY (game_id, module_id),
FOREIGN KEY (module_id) REFERENCES module(id) ON DELETE CASCADE,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TRIGGER tr_delete_game_to_module_module
AFTER DELETE ON game_to_module
FOR EACH ROW
BEGIN
DELETE FROM module
WHERE id = OLD.id
AND NOT EXISTS (SELECT 1 FROM game_to_module WHERE module_id = OLD.module_id);
END;
ALTER TABLE package_warnings ADD COLUMN game_id INTEGER REFERENCES game(id) ON DELETE CASCADE;
ALTER TABLE pack ADD COLUMN game_id INTEGER REFERENCES game(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS message (
id TEXT PRIMARY KEY,
blind BOOLEAN NOT NULL,
emote BOOLEAN NOT NULL,
style INTEGER NOT NULL,
timestamp DATETIME NOT NULL,
content VARCHAR(128) NOT NULL,
author VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
flavor VARCHAR(128) NOT NULL,
sound VARCHAR(128) NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS stats (
id INTEGER PRIMARY KEY AUTOINCREMENT,
core_version VARCHAR(128) NOT NULL,
system_id VARCHAR(128) NOT NULL,
system_version VARCHAR(128) NOT NULL,
last_modified_by VARCHAR(128) NOT NULL,
modified_time DATETIME NOT NULL,
message_id TEXT UNIQUE,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS speaker (
id INTEGER PRIMARY KEY AUTOINCREMENT,
scene VARCHAR(128) NOT NULL,
actor VARCHAR(128) NOT NULL,
token VARCHAR(128) NOT NULL,
alias VARCHAR(128) NOT NULL,
message_id TEXT UNIQUE,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS message_whisper (
id INTEGER PRIMARY KEY AUTOINCREMENT,
value VARCHAR(128) NOT NULL,
message_id TEXT,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS message_rolls (
id INTEGER PRIMARY KEY AUTOINCREMENT,
value VARCHAR(128) NOT NULL,
message_id TEXT,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS combat (
id TEXT PRIMARY KEY,
type VARCHAR(128) NOT NULL,
scene VARCHAR(128) NOT NULL,
round INTEGER NOT NULL,
turn INTEGER NOT NULL,
sort INTEGER NOT NULL,
active INTEGER NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN combat_id TEXT REFERENCES combat(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_combat_id ON stats(combat_id);
CREATE TABLE IF NOT EXISTS combat_groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
value VARCHAR(128) NOT NULL,
combat_id TEXT,
FOREIGN KEY (combat_id) REFERENCES combat(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS combatant (
id TEXT PRIMARY KEY,
token_id VARCHAR(128) NOT NULL,
scene_id VARCHAR(128) NOT NULL,
actor_id VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
group_ VARCHAR(128) NOT NULL,
initiative INTEGER NOT NULL,
hidden BOOLEAN NOT NULL,
defeated BOOLEAN NOT NULL,
combat_id TEXT,
FOREIGN KEY (combat_id) REFERENCES combat(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN combatant_id TEXT REFERENCES combatant(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_combatant_id ON stats(combatant_id);
CREATE TABLE IF NOT EXISTS card_deck (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
folder VARCHAR(128) NOT NULL,
width INTEGER NOT NULL,
height INTEGER NOT NULL,
rotation INTEGER NOT NULL,
sort INTEGER NOT NULL,
display_count BOOLEAN NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN card_deck_id TEXT REFERENCES card_deck(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_card_deck_id ON stats(card_deck_id);
CREATE TABLE IF NOT EXISTS ownership_string (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key_ VARCHAR(128) NOT NULL,
value INTEGER NOT NULL,
card_deck_id TEXT UNIQUE,
FOREIGN KEY (card_deck_id) REFERENCES card_deck(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS card (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
suit VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
origin VARCHAR(128) NOT NULL,
width INTEGER NOT NULL,
height INTEGER NOT NULL,
rotation INTEGER NOT NULL,
value INTEGER NOT NULL,
face INTEGER NOT NULL,
sort INTEGER NOT NULL,
drawn BOOLEAN NOT NULL,
card_deck_id TEXT,
FOREIGN KEY (card_deck_id) REFERENCES card_deck(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS back (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(128) NOT NULL,
text VARCHAR(128) NOT NULL,
card_id TEXT UNIQUE,
FOREIGN KEY (card_id) REFERENCES card(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN card_id TEXT REFERENCES card(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_card_id ON stats(card_id);
CREATE TABLE IF NOT EXISTS face (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
text VARCHAR(128) NOT NULL,
card_id TEXT,
FOREIGN KEY (card_id) REFERENCES card(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS user (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
avatar VARCHAR(128) NOT NULL,
character VARCHAR(128) NOT NULL,
color VARCHAR(128) NOT NULL,
pronouns VARCHAR(128) NOT NULL,
role INTEGER NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN user_id TEXT REFERENCES user(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_user_id ON stats(user_id);
CREATE TABLE IF NOT EXISTS hotbar (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key_ INTEGER NOT NULL,
value VARCHAR(128) NOT NULL,
user_id TEXT,
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS macro (
id TEXT PRIMARY KEY,
@@ -64,6 +324,163 @@ CREATE TABLE IF NOT EXISTS macro (
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN macro_id TEXT REFERENCES macro(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_macro_id ON stats(macro_id);
ALTER TABLE ownership_string ADD COLUMN macro_id TEXT REFERENCES macro(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS world_folder (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
folder VARCHAR(128) NOT NULL,
sorting VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
color VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN world_folder_id TEXT REFERENCES world_folder(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_world_folder_id ON stats(world_folder_id);
CREATE TABLE IF NOT EXISTS item (
id TEXT PRIMARY KEY,
img VARCHAR(128) NOT NULL,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
folder VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN item_id TEXT REFERENCES item(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_item_id ON stats(item_id);
ALTER TABLE ownership_string ADD COLUMN item_id TEXT REFERENCES item(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS setting (
id TEXT PRIMARY KEY,
key_ VARCHAR(128) NOT NULL,
value VARCHAR(128) NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN setting_id TEXT REFERENCES setting(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_setting_id ON stats(setting_id);
CREATE TABLE IF NOT EXISTS journal (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS journal_page (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
src VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
journal_id TEXT,
FOREIGN KEY (journal_id) REFERENCES journal(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS journal_page_text (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content VARCHAR(128) NOT NULL,
markdown VARCHAR(128) NOT NULL,
format INTEGER NOT NULL,
journal_page_id TEXT,
FOREIGN KEY (journal_page_id) REFERENCES journal_page(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS journal_page_title (
id INTEGER PRIMARY KEY AUTOINCREMENT,
show BOOLEAN NOT NULL,
level INTEGER NOT NULL,
journal_page_id TEXT,
FOREIGN KEY (journal_page_id) REFERENCES journal_page(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS journal_page_video (
id INTEGER PRIMARY KEY AUTOINCREMENT,
controls BOOLEAN NOT NULL,
volume REAL NOT NULL,
journal_page_id TEXT,
FOREIGN KEY (journal_page_id) REFERENCES journal_page(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN journal_page_id TEXT REFERENCES journal_page(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_journal_page_id ON stats(journal_page_id);
ALTER TABLE ownership_string ADD COLUMN journal_page_id TEXT REFERENCES journal_page(id) ON DELETE CASCADE;
ALTER TABLE ownership_string ADD COLUMN journal_id TEXT REFERENCES journal(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS table_ (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
formula VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
folder VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
replacement BOOLEAN NOT NULL,
display_roll BOOLEAN NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN table_id TEXT REFERENCES table_(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_table_id ON stats(table_id);
ALTER TABLE ownership_string ADD COLUMN table_id TEXT REFERENCES table_(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS table_result (
id TEXT PRIMARY KEY,
type VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
name VARCHAR(128) NOT NULL,
weight INTEGER NOT NULL,
drawn BOOLEAN NOT NULL,
table_id TEXT,
FOREIGN KEY (table_id) REFERENCES table_(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN table_result_id TEXT REFERENCES table_result(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_table_result_id ON stats(table_result_id);
CREATE TABLE IF NOT EXISTS table_result_range (
id INTEGER PRIMARY KEY AUTOINCREMENT,
value INTEGER NOT NULL,
table_result_id TEXT,
FOREIGN KEY (table_result_id) REFERENCES table_result(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS playlist (
id TEXT PRIMARY KEY,
@@ -82,6 +499,10 @@ CREATE TABLE IF NOT EXISTS playlist (
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN playlist_id TEXT REFERENCES playlist(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_playlist_id ON stats(playlist_id);
ALTER TABLE ownership_string ADD COLUMN playlist_id TEXT REFERENCES playlist(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS sound (
id TEXT PRIMARY KEY,
@@ -113,8 +534,13 @@ CREATE TABLE IF NOT EXISTS actor (
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
ALTER TABLE stats ADD COLUMN actor_id TEXT REFERENCES actor(id) ON DELETE CASCADE;
CREATE UNIQUE INDEX idx_stats_actor_id ON stats(actor_id);
ALTER TABLE ownership_string ADD COLUMN actor_id TEXT REFERENCES actor(id) ON DELETE CASCADE;
ALTER TABLE item ADD COLUMN actor_id TEXT REFERENCES actor(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS token (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(128) NOT NULL,
actor_link BOOLEAN NOT NULL,
@@ -179,6 +605,43 @@ CREATE TABLE IF NOT EXISTS token_sight (
FOREIGN KEY (token_id) REFERENCES token(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS token_texture (
id INTEGER PRIMARY KEY AUTOINCREMENT,
src VARCHAR(128) NOT NULL,
fit VARCHAR(128) NOT NULL,
tint VARCHAR(128) NOT NULL,
scale_x REAL NOT NULL,
scale_y REAL NOT NULL,
offset_x REAL NOT NULL,
offset_y REAL NOT NULL,
rotation REAL NOT NULL,
anchor_x REAL NOT NULL,
anchor_y REAL NOT NULL,
alpha_threshold REAL NOT NULL,
token_id INTEGER UNIQUE,
FOREIGN KEY (token_id) REFERENCES token(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS token_bar_1 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
attribute VARCHAR(128) NOT NULL,
token_id INTEGER UNIQUE,
FOREIGN KEY (token_id) REFERENCES token(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS token_bar_2 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
attribute VARCHAR(128) NOT NULL,
token_id INTEGER UNIQUE,
FOREIGN KEY (token_id) REFERENCES token(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS token_light (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -221,43 +684,6 @@ CREATE TABLE IF NOT EXISTS token_light_darkness (
FOREIGN KEY (token_light_id) REFERENCES token_light(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS token_texture (
id INTEGER PRIMARY KEY AUTOINCREMENT,
src VARCHAR(128) NOT NULL,
fit VARCHAR(128) NOT NULL,
tint VARCHAR(128) NOT NULL,
scale_x REAL NOT NULL,
scale_y REAL NOT NULL,
offset_x REAL NOT NULL,
offset_y REAL NOT NULL,
rotation REAL NOT NULL,
anchor_x REAL NOT NULL,
anchor_y REAL NOT NULL,
alpha_threshold REAL NOT NULL,
token_id INTEGER UNIQUE,
FOREIGN KEY (token_id) REFERENCES token(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS token_bar_1 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
attribute VARCHAR(128) NOT NULL,
token_id INTEGER UNIQUE,
FOREIGN KEY (token_id) REFERENCES token(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS token_bar_2 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
attribute VARCHAR(128) NOT NULL,
token_id INTEGER UNIQUE,
FOREIGN KEY (token_id) REFERENCES token(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS token_occludable (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -278,384 +704,3 @@ CREATE TABLE IF NOT EXISTS token_turn_maker (
token_id INTEGER UNIQUE,
FOREIGN KEY (token_id) REFERENCES token(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS table_ (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
formula VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
folder VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
replacement BOOLEAN NOT NULL,
display_roll BOOLEAN NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS table_result (
id TEXT PRIMARY KEY,
type VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
name VARCHAR(128) NOT NULL,
weight INTEGER NOT NULL,
drawn BOOLEAN NOT NULL,
table_id INTEGER,
FOREIGN KEY (table_id) REFERENCES table_(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS table_result_range (
id INTEGER PRIMARY KEY AUTOINCREMENT,
range_ INTEGER NOT NULL,
table_result_id INTEGER,
FOREIGN KEY (table_result_id) REFERENCES table_result(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS user (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
avatar VARCHAR(128) NOT NULL,
character VARCHAR(128) NOT NULL,
color VARCHAR(128) NOT NULL,
pronouns VARCHAR(128) NOT NULL,
role INTEGER NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS setting (
id TEXT PRIMARY KEY,
key_ VARCHAR(128) NOT NULL,
value VARCHAR(128) NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS hotbar (
id INTEGER PRIMARY KEY,
key_ INTEGER NOT NULL,
value VARCHAR(128) NOT NULL,
user_id TEXT,
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS active_users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
users VARCHAR(128) NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS item (
id TEXT PRIMARY KEY,
img VARCHAR(128) NOT NULL,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
folder VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE,
actor_id TEXT,
FOREIGN KEY (actor_id) REFERENCES actor(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS journal (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
game_id INTEGER UNIQUE,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS world_folder (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
folder VARCHAR(128) NOT NULL,
sorting VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
color VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS message (
id TEXT PRIMARY KEY,
blind BOOLEAN NOT NULL,
emote BOOLEAN NOT NULL,
style INTEGER NOT NULL,
timestamp DATETIME NOT NULL,
content VARCHAR(128) NOT NULL,
author VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
flavor VARCHAR(128) NOT NULL,
sound VARCHAR(128) NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS combat (
id TEXT PRIMARY KEY,
type VARCHAR(128) NOT NULL,
scene VARCHAR(128) NOT NULL,
round INTEGER NOT NULL,
turn INTEGER NOT NULL,
sort INTEGER NOT NULL,
active INTEGER NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS card_deck (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
folder VARCHAR(128) NOT NULL,
width INTEGER NOT NULL,
height INTEGER NOT NULL,
rotation INTEGER NOT NULL,
sort INTEGER NOT NULL,
display_count BOOLEAN NOT NULL,
game_id INTEGER,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS combatant (
id TEXT PRIMARY KEY,
token_id VARCHAR(128) NOT NULL,
scene_id VARCHAR(128) NOT NULL,
actor_id VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
group_ VARCHAR(128) NOT NULL,
initiative INTEGER NOT NULL,
hidden BOOLEAN NOT NULL,
defeated BOOLEAN NOT NULL,
combat_id TEXT,
FOREIGN KEY (combat_id) REFERENCES combat(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS stats (
id INTEGER PRIMARY KEY AUTOINCREMENT,
core_version VARCHAR(128) NOT NULL,
system_id VARCHAR(128) NOT NULL,
system_version VARCHAR(128) NOT NULL,
last_modified_by VARCHAR(128) NOT NULL,
modified_time DATETIME NOT NULL,
message_id TEXT UNIQUE,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE,
combat_id TEXT UNIQUE,
FOREIGN KEY (combat_id) REFERENCES combat(id) ON DELETE CASCADE,
combatant_id TEXT UNIQUE,
FOREIGN KEY (combatant_id) REFERENCES combatant(id) ON DELETE CASCADE,
card_deck_id TEXT UNIQUE,
FOREIGN KEY (card_deck_id) REFERENCES card_deck(id) ON DELETE CASCADE,
card_id TEXT UNIQUE,
FOREIGN KEY (card_id) REFERENCES card(id) ON DELETE CASCADE,
user_id TEXT UNIQUE,
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE,
macro_id TEXT UNIQUE,
FOREIGN KEY (macro_id) REFERENCES macro(id) ON DELETE CASCADE,
world_folder_id TEXT UNIQUE,
FOREIGN KEY (world_folder_id) REFERENCES world_folder(id) ON DELETE CASCADE,
item_id TEXT UNIQUE,
FOREIGN KEY (item_id) REFERENCES item(id) ON DELETE CASCADE,
setting_id TEXT UNIQUE,
FOREIGN KEY (setting_id) REFERENCES setting(id) ON DELETE CASCADE,
journal_page_id TEXT UNIQUE,
FOREIGN KEY (journal_page_id) REFERENCES journal_page(id) ON DELETE CASCADE,
table_id TEXT UNIQUE,
FOREIGN KEY (table_id) REFERENCES table_(id) ON DELETE CASCADE,
table_result_id TEXT UNIQUE,
FOREIGN KEY (table_result_id) REFERENCES table_result(id) ON DELETE CASCADE,
playlist_id TEXT UNIQUE,
FOREIGN KEY (playlist_id) REFERENCES playlist(id) ON DELETE CASCADE,
actor_id TEXT UNIQUE,
FOREIGN KEY (actor_id) REFERENCES actor(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS speaker (
id INTEGER PRIMARY KEY AUTOINCREMENT,
scene VARCHAR(128) NOT NULL,
actor VARCHAR(128) NOT NULL,
token VARCHAR(128) NOT NULL,
alias VARCHAR(128) NOT NULL,
message_id TEXT UNIQUE,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS combat_groups (
id TEXT PRIMARY KEY,
groups_ VARCHAR(128) NOT NULL,
combat_id TEXT,
FOREIGN KEY (combat_id) REFERENCES combat(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS card (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
suit VARCHAR(128) NOT NULL,
description VARCHAR(128) NOT NULL,
origin VARCHAR(128) NOT NULL,
width INTEGER NOT NULL,
height INTEGER NOT NULL,
rotation INTEGER NOT NULL,
value INTEGER NOT NULL,
face INTEGER NOT NULL,
sort INTEGER NOT NULL,
drawn BOOLEAN NOT NULL,
card_deck_id TEXT,
FOREIGN KEY (card_deck_id) REFERENCES card_deck(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS back (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(128) NOT NULL,
text VARCHAR(128) NOT NULL,
card_id TEXT UNIQUE,
FOREIGN KEY (card_id) REFERENCES card(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS face (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(128) NOT NULL,
img VARCHAR(128) NOT NULL,
text VARCHAR(128) NOT NULL,
card_id TEXT,
FOREIGN KEY (card_id) REFERENCES card(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS message_whisper (
id TEXT PRIMARY KEY,
value VARCHAR(128) NOT NULL,
message_id TEXT,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS message_rolls (
id TEXT PRIMARY KEY,
value VARCHAR(128) NOT NULL,
message_id TEXT,
FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS journal_page (
id TEXT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type VARCHAR(128) NOT NULL,
src VARCHAR(128) NOT NULL,
sort INTEGER NOT NULL,
journal_id TEXT,
FOREIGN KEY (journal_id) REFERENCES journal(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS journal_page_text (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content VARCHAR(128) NOT NULL,
markdown VARCHAR(128) NOT NULL,
format INTEGER NOT NULL,
journal_page_id TEXT,
FOREIGN KEY (journal_page_id) REFERENCES journal_page(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS journal_page_title (
id INTEGER PRIMARY KEY AUTOINCREMENT,
show BOOLEAN NOT NULL,
level INTEGER NOT NULL,
journal_page_id TEXT,
FOREIGN KEY (journal_page_id) REFERENCES journal_page(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS journal_page_video (
id INTEGER PRIMARY KEY AUTOINCREMENT,
controls BOOLEAN NOT NULL,
volume REAL NOT NULL,
journal_page_id TEXT,
FOREIGN KEY (journal_page_id) REFERENCES journal_page(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS ownership_string (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key_ VARCHAR(128) NOT NULL,
value INTEGER NOT NULL,
macro_id TEXT,
FOREIGN KEY (macro_id) REFERENCES macro(id) ON DELETE CASCADE,
item_id TEXT,
FOREIGN KEY (item_id) REFERENCES item(id) ON DELETE CASCADE,
journal_id TEXT,
FOREIGN KEY (journal_id) REFERENCES journal(id) ON DELETE CASCADE,
playlist_id TEXT,
FOREIGN KEY (playlist_id) REFERENCES playlist(id) ON DELETE CASCADE,
actor_id TEXT,
FOREIGN KEY (actor_id) REFERENCES actor(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS system_update (
id INTEGER PRIMARY KEY AUTOINCREMENT,
has_update BOOLEAN NOT NULL DEFAULT FALSE,
version VARCHAR(128) NOT NULL,
game_id INTEGER UNIQUE,
FOREIGN KEY (game_id) REFERENCES game(id) ON DELETE CASCADE
);

View File

@@ -6,4 +6,5 @@ var (
ErrActionNotFound = errors.New("Action doesn't found")
ErrObjTypeNotMatch = errors.New("Provided value type didn't match obj field type")
ErrObjNotPointer = errors.New("Passed obj is not pointer")
ErrUserChannelIsClosed = errors.New("User channel is closed")
)

View File

@@ -1,6 +1,8 @@
package actions
import (
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/temp_models/db"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/temp_models/json"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/transport"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/types"
)
@@ -22,8 +24,18 @@ func (msg WsSessionMsg) Action(tr *transport.FoundryTransport, status *types.Fou
close(tr.ReadChan.Reconnect())
return nil
}
// tr.Logger.Warn("World is started. Please, return to setup page to fully initialize database")
// go msg.OnActiveWorld(tr)
// select {
// case <-tr.LoggedInChan:
// return ErrUserChannelIsClosed
// default:
// tr.LoggedInChan <- true
// }
// time.Sleep(3 * time.Second)
// types.CloseChannel(tr.LoggedInChan)
go msg.OnActiveWorld(tr)
return nil
}
@@ -37,13 +49,27 @@ func (msg WsSessionMsg) Action(tr *transport.FoundryTransport, status *types.Fou
}
func (msg WsSessionMsg) OnActiveWorld(tr *transport.FoundryTransport) error {
wsMsg := types.NewWsMessage("world", tr.CurrWsId)
tr.CurrWsId++
answer, err := tr.HandleWebsocketRequest(wsMsg)
msgJson, err := tr.GetJsonData("world")
if err != nil {
return err
}
tr.Logger.Info("World data", "answer", string(answer))
tr.Logger.Info("Game data received")
gameJson, err := json.ParseGame(msgJson)
if err != nil {
return err
}
var foundryStateDb db.Game
gameJson.ToDB(&foundryStateDb)
err = foundryStateDb.Insert(tr.DB)
if err != nil {
tr.ReadChan.Err() <- &types.FoundryError{Direction: types.WriterCode, Err: err, Type: types.DbCode}
}
tr.Logger.Info("Game data succesfully inserted to DB")
return nil
}

View File

@@ -1,5 +1,15 @@
package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Actor struct {
ID string
@@ -8,8 +18,60 @@ type Actor struct {
Type string
Folder string
Sort int
PrototypeToken Token
PrototypeToken *Token
Stats Stats
Items []*Item
Ownership []OwnershipString
}
func (a *Actor) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO actor (%s, id, img, name, type, folder, sort)
VALUES ($1, $2, $3, $4, $5, $6, $7)`, data.fieldName)
}
func (a *Actor) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[string]{id: a.ID, fieldName: "actor_id"}
InsertWithCtxParallel(group, ctx, tx, a.PrototypeToken, relId)
InsertWithCtxParallel(group, ctx, tx, a.Stats, relId)
InsertSliceParallel(group, tx, a.Ownership, relId)
InsertSliceParallel(group, tx, a.Items, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (a *Actor) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, a.ID, a.Img, a.Name, a.Type, a.Folder, a.Sort}
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return a.InsertObjects(tx)
}
func (a *Actor) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, a.ID, a.Img, a.Name, a.Type, a.Folder, a.Sort}
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return a.InsertObjects(tx)
}

View File

@@ -23,7 +23,7 @@ type CardDeck struct {
Sort int
DisplayCount bool
Stats Stats
Ownership Ownership
Ownership []OwnershipString
Cards []*Card
}
@@ -38,7 +38,7 @@ func (c *CardDeck) InsertObjects(tx *sqlx.Tx) error {
relId := InsertId[string]{id: c.ID, fieldName: "card_deck_id"}
InsertWithCtxParallel(group, ctx, tx, c.Stats, relId)
InsertWithCtxParallel(group, ctx, tx, c.Ownership, relId)
InsertSliceParallel(group, tx, c.Ownership, relId)
InsertSliceParallel(group, tx, c.Cards, relId)
err := group.Wait()

View File

@@ -41,9 +41,9 @@ type Game struct {
Items []*Item
Settings []*Setting
Journals []*Journal
Tables []*Table //
Tables []*Table
Playlists []*Playlist
Actors []Actor //
Actors []*Actor
// Scenes []Scene
}
@@ -62,22 +62,25 @@ func (g *Game) InsertObjects(tx *sqlx.Tx) error {
InsertWithCtxParallel(group, ctx, tx, g.World, relDataString)
InsertWithCtxParallel(group, ctx, tx, g.System, relDataString)
InsertSimpleSliceParallel(group, tx, g.ActiveUsers, &InsertId[uint]{id: g.ID, fieldName: "game_id", tableName: "active_users"})
InsertSimpleSliceParallel(group, tx, g.ActiveUsers,
&InsertId[uint]{id: g.ID, fieldName: "game_id", tableName: "active_users"})
InsertSliceParallel(group, tx, g.Modules, relData)
InsertSliceParallel(group, tx, g.PackageWarnings, relData)
InsertSliceParallel(group, tx, g.Packs, relDataString)
InsertSliceParallel(group, tx, g.Messages, relData)
InsertSliceParallel(group, tx, g.Combats, relData)
InsertSliceParallel(group, tx, g.CardDeck, relData)
InsertSliceParallel(group, tx, g.Users, relData)
InsertSliceParallel(group, tx, g.Macros, relData)
InsertSliceParallel(group, tx, g.Folders, relData)
InsertSliceParallel(group, tx, g.Items, relData)
InsertSliceParallel(group, tx, g.Settings, relData)
InsertSliceParallel(group, tx, g.Journals, relData)
InsertSliceParallel(group, tx, g.Tables, relData)
InsertSliceParallel(group, tx, g.Playlists, relData)
// InsertSliceParallel(group, tx, g.Messages, relData)
// InsertSliceParallel(group, tx, g.Combats, relData)
// InsertSliceParallel(group, tx, g.CardDeck, relData)
// InsertSliceParallel(group, tx, g.Users, relData)
// InsertSliceParallel(group, tx, g.Macros, relData)
// InsertSliceParallel(group, tx, g.Folders, relData)
// InsertSliceParallel(group, tx, g.Items,
// InsertId[string]{id: strconv.FormatUint(uint64(g.ID), 10), fieldName: "game_id"})
// InsertSliceParallel(group, tx, g.Settings, relData)
// InsertSliceParallel(group, tx, g.Journals, relData)
// InsertSliceParallel(group, tx, g.Tables, relData)
// InsertSliceParallel(group, tx, g.Playlists, relData)
// InsertSliceParallel(group, tx, g.Actors, relData)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {

View File

@@ -15,14 +15,14 @@ type Index struct {
Type string
}
func (i *Index) Query(data *InsertId[uint]) {
func (i *Index) Query(data *InsertId[string]) {
data.query = `
INSERT INTO index_ (pack_id, id, folder, img, name, type)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id`
}
func (i *Index) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
func (i *Index) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
@@ -37,7 +37,7 @@ func (i *Index) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
return nil
}
func (i *Index) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
func (i *Index) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}

View File

@@ -22,7 +22,7 @@ type Item struct {
Ownership []OwnershipString
}
func (i *Item) Query(data *InsertId[uint]) {
func (i *Item) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO world_folder (%s, id, img, name, type, folder, sort)
VALUES ($1, $2, $3, $4, $5, $6, $7)
@@ -43,7 +43,7 @@ func (i *Item) InsertObjects(tx *sqlx.Tx) error {
return nil
}
func (i *Item) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
func (i *Item) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
@@ -58,7 +58,7 @@ func (i *Item) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
return i.InsertObjects(tx)
}
func (i *Item) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
func (i *Item) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}

View File

@@ -1,5 +1,15 @@
package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Light struct {
ID uint
@@ -20,6 +30,60 @@ type Light struct {
LightDarkness LightDarkness
}
func (l *Light) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO token_light (%s, color, priority, angle, negative, alpha, bright, coloration, dim,
attenuation, luminosity, saturation, contrast, shadows)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
RETURNING id`, data.fieldName)
}
func (l *Light) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[uint]{id: l.ID, fieldName: "token_light_id"}
InsertWithCtxParallel(group, ctx, tx, l.LightAnimation, relId)
InsertWithCtxParallel(group, ctx, tx, l.LightDarkness, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (l *Light) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, l.Color, l.Priority, l.Angle, l.Negative, l.Alpha, l.Bright, l.Coloration, l.Dim,
l.Attenuation, l.Luminosity, l.Saturation, l.Contrast, l.Shadows}
err := tx.QueryRowx(data.query, args...).Scan(&l.ID)
if err != nil {
return err
}
return nil
}
func (l *Light) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, l.Color, l.Priority, l.Angle, l.Negative, l.Alpha, l.Bright, l.Coloration, l.Dim,
l.Attenuation, l.Luminosity, l.Saturation, l.Contrast, l.Shadows}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&l.ID)
if err != nil {
return err
}
return nil
}
type LightAnimation struct {
ID uint
@@ -27,9 +91,84 @@ type LightAnimation struct {
Intensity int
Reverse bool
}
func (l LightAnimation) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO token_light_animation (%s, speed, intensity, reverse)
VALUES ($1, $2, $3, $4)
RETURNING id`, data.fieldName)
}
func (l LightAnimation) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, l.Speed, l.Intensity, l.Reverse}
err := tx.QueryRowx(data.query, args...).Scan(&l.ID)
if err != nil {
return err
}
return nil
}
func (l LightAnimation) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, l.Speed, l.Intensity, l.Reverse}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&l.ID)
if err != nil {
return err
}
return nil
}
type LightDarkness struct {
ID uint
Min float64
Max float64
}
func (l LightDarkness) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO token_light_darkness (%s, min, max)
VALUES ($1, $2, $3, $4)
RETURNING id`, data.fieldName)
}
func (l LightDarkness) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, l.Min, l.Max}
err := tx.QueryRowx(data.query, args...).Scan(&l.ID)
if err != nil {
return err
}
return nil
}
func (l LightDarkness) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, l.Min, l.Max}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&l.ID)
if err != nil {
return err
}
return nil
}

View File

@@ -4,7 +4,7 @@ import (
"context"
"database/sql"
"errors"
"fmt"
"strings"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
@@ -49,12 +49,19 @@ type Module struct {
}
func (m *Module) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO module (%s, id, title, description, url, license, readme, bugs,
data.query = `
INSERT INTO module (setup_id, id, title, description, url, license, readme, bugs,
changelog, version, manifest, download, socket, protected, exclusive_, persistent_storage,
core_translation, library, locked, owned, has_storage, active, availability)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17,
$18, $19, $20, $21, $22, $23)`, data.fieldName)
$18, $19, $20, $21, $22, $23)
ON CONFLICT(id) DO NOTHING`
}
func (m *Module) ConnectGameQuery(data *InsertId[uint]) {
data.query = `
INSERT INTO game_to_module (game_id, module_id)
VALUES ($1, $2)`
}
func (m *Module) InsertObjects(tx *sqlx.Tx) error {
@@ -65,19 +72,19 @@ func (m *Module) InsertObjects(tx *sqlx.Tx) error {
InsertWithCtxParallel(group, ctx, tx, m.Relationships, relId)
InsertWithCtxParallel(group, ctx, tx, m.Compatibility, relId)
// scriptRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "scripts"}
// InsertSimpleSliceParallel(group, tx, m.Scripts, scriptRelId)
// esModulesRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "es_modules"}
// InsertSimpleSliceParallel(group, tx, m.Esmodules, esModulesRelId)
// tagsRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "tags"}
// InsertSimpleSliceParallel(group, tx, m.Tags, tagsRelId)
scriptRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "scripts"}
InsertSimpleSliceParallel(group, tx, m.Scripts, scriptRelId)
esModulesRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "es_modules"}
InsertSimpleSliceParallel(group, tx, m.Esmodules, esModulesRelId)
tagsRelId := &InsertId[string]{id: m.ID, fieldName: "module_id", tableName: "tags"}
InsertSimpleSliceParallel(group, tx, m.Tags, tagsRelId)
// InsertSliceParallel(group, tx, m.Authors, relId)
// InsertSliceParallel(group, tx, m.Media, relId)
// InsertSliceParallel(group, tx, m.Styles, relId)
// InsertSliceParallel(group, tx, m.Languages, relId)
// InsertSliceParallel(group, tx, m.Packs, relId)
// InsertSliceParallel(group, tx, m.PackFolders, relId)
InsertSliceParallel(group, tx, m.Authors, relId)
InsertSliceParallel(group, tx, m.Media, relId)
InsertSliceParallel(group, tx, m.Styles, relId)
InsertSliceParallel(group, tx, m.Languages, relId)
InsertSliceParallel(group, tx, m.Packs, relId)
InsertSliceParallel(group, tx, m.PackFolders, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
@@ -86,21 +93,56 @@ func (m *Module) InsertObjects(tx *sqlx.Tx) error {
return nil
}
func (m *Module) ConnectGame(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, m.ID}
_, err := tx.Exec(data.query, args...)
return err
}
func (m *Module) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, m.ID, m.Title, m.Description, m.URL, m.License, m.Readme, m.Bugs,
setupID := sql.NullInt64{Int64: int64(data.id), Valid: strings.EqualFold(data.fieldName, "setup_id")}
args := []any{setupID, data.id, m.ID, m.Title, m.Description, m.URL, m.License, m.Readme, m.Bugs,
m.Changelog, m.Version, m.Manifest, m.Download, m.Socket, m.Protected, m.Exclusive, m.PersistentStorage,
m.CoreTranslation, m.Library, m.Locked, m.Owned, m.HasStorage, m.Active, m.Availability}
_, err := tx.Exec(data.query, args...)
res, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return m.InsertObjects(tx)
rowsAffected, err := res.RowsAffected()
if rowsAffected != 0 {
err = m.InsertObjects(tx)
if err != nil {
return err
}
}
dataCopy := *data
m.ConnectGameQuery(&dataCopy)
return m.ConnectGame(tx, &dataCopy)
}
func (m *Module) ConnectGameCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, m.ID}
_, err := tx.ExecContext(ctx, data.query, args...)
return err
}
func (m *Module) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
@@ -108,14 +150,27 @@ func (m *Module) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint
return ErrNoQuery
}
args := []any{data.id, m.ID, m.Title, m.Description, m.URL, m.License, m.Readme, m.Bugs,
setupID := sql.NullInt64{Int64: int64(data.id), Valid: strings.EqualFold(data.fieldName, "setup_id")}
args := []any{setupID, data.id, m.ID, m.Title, m.Description, m.URL, m.License, m.Readme, m.Bugs,
m.Changelog, m.Version, m.Manifest, m.Download, m.Socket, m.Protected, m.Exclusive, m.PersistentStorage,
m.CoreTranslation, m.Library, m.Locked, m.Owned, m.HasStorage, m.Active, m.Availability}
_, err := tx.ExecContext(ctx, data.query, args...)
res, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return m.InsertObjects(tx)
rowsAffected, err := res.RowsAffected()
if rowsAffected != 0 {
err = m.InsertObjects(tx)
if err != nil {
return err
}
}
dataCopy := *data
m.ConnectGameQuery(&dataCopy)
return m.ConnectGameCtx(ctx, tx, &dataCopy)
}

View File

@@ -16,7 +16,7 @@ type GameOptions struct {
func (g *GameOptions) Query(data *InsertId[uint]) {
data.query = `
INSERT INTO featured_content (game_id, language, update_channel, port)
INSERT INTO game_options (game_id, language, update_channel, port)
VALUES ($1, $2, $3, $4)
RETURNING id`
}

View File

@@ -5,16 +5,14 @@ import (
"database/sql"
"errors"
"fmt"
"strconv"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Pack struct {
ID uint
ID string
Key string
Name string
Label string
Banner string
@@ -30,18 +28,17 @@ type Pack struct {
func (p *Pack) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO pack (%s, key_, name, label, banner, path, type, system, package_type, package_name)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id`, data.fieldName)
INSERT INTO pack (%s, id, name, label, banner, path, type, system, package_type, package_name)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, data.fieldName)
}
func (p *Pack) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
InsertWithCtxParallel(group, ctx, tx, p.Ownership,
InsertId[string]{id: strconv.FormatUint(uint64(p.ID), 10), fieldName: "pack_id"})
InsertId[string]{id: p.ID, fieldName: "pack_id"})
relId := InsertId[uint]{id: p.ID, fieldName: "pack_id"}
relId := InsertId[string]{id: p.ID, fieldName: "pack_id"}
InsertSliceParallel(group, tx, p.Index, relId)
InsertSliceParallel(group, tx, p.Folders, relId)
@@ -57,9 +54,10 @@ func (p *Pack) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
return ErrNoQuery
}
args := []any{data.id, p.Key, p.Name, p.Label, p.Banner, p.Path, p.Type, p.System, p.PackageType, p.PackageName}
args := []any{data.id, p.ID, p.Name, p.Label, p.Banner, p.Path, p.Type,
p.System, p.PackageType, p.PackageName}
err := tx.QueryRowx(data.query, args...).Scan(&p.ID)
_, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
@@ -72,9 +70,10 @@ func (p *Pack) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string
return ErrNoQuery
}
args := []any{data.id, p.Key, p.Name, p.Label, p.Banner, p.Path, p.Type, p.System, p.PackageType, p.PackageName}
args := []any{data.id, p.ID, p.Name, p.Label, p.Banner, p.Path, p.Type,
p.System, p.PackageType, p.PackageName}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&p.ID)
_, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
@@ -92,13 +91,13 @@ type PackFolder struct {
Sort int
}
func (p *PackFolder) Query(data *InsertId[uint]) {
func (p *PackFolder) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO pack_folder (%s, id, description, name, sorting, type, sort)
VALUES ($1, $2, $3, $4, $5, $6, $7)`, data.fieldName)
}
func (p *PackFolder) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
func (p *PackFolder) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
@@ -113,7 +112,7 @@ func (p *PackFolder) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
return nil
}
func (p *PackFolder) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
func (p *PackFolder) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}

View File

@@ -83,8 +83,26 @@ func (p *PackageWarningsData) InsertObjects(tx *sqlx.Tx) error {
func (p *PackageWarningsData) Query(data *InsertId[uint]) {
data.query = `
INSERT INTO package_warnings_data (package_warnings_id, id, type, reinstallable, manifest)
VALUES ($1, $2, $3, $4, $5)`
INSERT INTO package_warnings_data (id, type, reinstallable, manifest)
VALUES ($1, $2, $3, $4)
ON CONFLICT(id) DO NOTHING`
}
func (p *PackageWarningsData) ConnectGameQuery(data *InsertId[uint]) {
data.query = `
INSERT INTO package_warnings_to_data (package_warnings_id, package_warnings_data_id)
VALUES ($1, $2)`
}
func (p *PackageWarningsData) ConnectGame(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.ID}
_, err := tx.Exec(data.query, args...)
return err
}
func (p *PackageWarningsData) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
@@ -92,14 +110,36 @@ func (p *PackageWarningsData) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
return ErrNoQuery
}
args := []any{data.id, p.ID, p.Type, p.Reinstallable, p.Manifest}
args := []any{p.ID, p.Type, p.Reinstallable, p.Manifest}
_, err := tx.Exec(data.query, args...)
res, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return p.InsertObjects(tx)
rowsAffected, err := res.RowsAffected()
if rowsAffected != 0 {
err = p.InsertObjects(tx)
}
if err != nil {
return err
}
dataCopy := *data
p.ConnectGameQuery(&dataCopy)
return p.ConnectGame(tx, &dataCopy)
}
func (p *PackageWarningsData) ConnectGameCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, p.ID}
_, err := tx.ExecContext(ctx, data.query, args...)
return err
}
func (p *PackageWarningsData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
@@ -107,12 +147,23 @@ func (p *PackageWarningsData) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *
return ErrNoQuery
}
args := []any{data.id, p.ID, p.Type, p.Reinstallable, p.Manifest}
args := []any{p.ID, p.Type, p.Reinstallable, p.Manifest}
_, err := tx.ExecContext(ctx, data.query, args...)
res, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return p.InsertObjects(tx)
rowsAffected, err := res.RowsAffected()
if rowsAffected != 0 {
err = p.InsertObjects(tx)
}
if err != nil {
return err
}
dataCopy := *data
p.ConnectGameQuery(&dataCopy)
return p.ConnectGameCtx(ctx, tx, &dataCopy)
}

View File

@@ -1,5 +1,15 @@
package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Ring struct {
ID uint
@@ -9,6 +19,57 @@ type Ring struct {
Subject Subject
}
func (r *Ring) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO ring (%s, enabled, effects)
VALUES ($1, $2, $3)
RETURNING id`, data.fieldName)
}
func (r *Ring) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[uint]{id: r.ID, fieldName: "ring_id"}
InsertWithCtxParallel(group, ctx, tx, r.RingColors, relId)
InsertWithCtxParallel(group, ctx, tx, r.Subject, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (r *Ring) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, r.Enabled, r.Effects}
err := tx.QueryRowx(data.query, args...).Scan(&r.ID)
if err != nil {
return err
}
return nil
}
func (r *Ring) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, r.Enabled, r.Effects}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&r.ID)
if err != nil {
return err
}
return nil
}
type RingColors struct {
ID uint
@@ -16,9 +77,83 @@ type RingColors struct {
Background string
}
func (r RingColors) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO ring_colors (%s, ring, background)
VALUES ($1, $2, $3)
RETURNING id`, data.fieldName)
}
func (r RingColors) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, r.Ring, r.Background}
err := tx.QueryRowx(data.query, args...).Scan(&r.ID)
if err != nil {
return err
}
return nil
}
func (r RingColors) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, r.Ring, r.Background}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&r.ID)
if err != nil {
return err
}
return nil
}
type Subject struct {
ID uint
Scale int
Texture string
}
func (s Subject) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO ring_colors (%s, scale, texture)
VALUES ($1, $2, $3)
RETURNING id`, data.fieldName)
}
func (s Subject) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.Scale, s.Texture}
err := tx.QueryRowx(data.query, args...).Scan(&s.ID)
if err != nil {
return err
}
return nil
}
func (s Subject) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.Scale, s.Texture}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&s.ID)
if err != nil {
return err
}
return nil
}

View File

@@ -21,7 +21,7 @@ type Scene struct {
Grid SceneGrid
TokenVision bool
Drawings []SceneDrawing
Tokens []Token
Tokens []*Token
Lights []SceneLight
Notes []Note
Sounds []ScenesSound
@@ -119,7 +119,7 @@ type SceneLight struct {
Rotation int
Walls bool
Vision bool
Config Light
Config *Light
Hidden bool
Elevation int
}

View File

@@ -4,7 +4,7 @@ import (
"context"
"database/sql"
"errors"
"fmt"
"strings"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
@@ -48,12 +48,18 @@ type System struct {
}
func (s *System) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO system (%s, id, title, description, url, license, bugs, changelog, version, manifest,
data.query = `
INSERT INTO system (setup_id, id, title, description, url, license, bugs, changelog, version, manifest,
download, background, primary_token_attribute, availability, socket, protected, exclusive_,
persistent_storage, locked, owned, has_storage)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)`,
data.fieldName)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)
ON CONFLICT(id) DO NOTHING`
}
func (s *System) ConnectGameQuery(data *InsertId[string]) {
data.query = `
INSERT INTO game_to_systems (game_id, system_id)
VALUES ($1, $2)`
}
func (s *System) InsertObjects(tx *sqlx.Tx) error {
@@ -86,22 +92,57 @@ func (s *System) InsertObjects(tx *sqlx.Tx) error {
return nil
}
func (s *System) ConnectGame(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.ID}
_, err := tx.Exec(data.query, args...)
return err
}
func (s *System) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.ID, s.Title, s.Description, s.URL, s.License, s.Bugs,
setupID := sql.NullString{String: data.id, Valid: strings.EqualFold(data.fieldName, "setup_id")}
args := []any{setupID, s.ID, s.Title, s.Description, s.URL, s.License, s.Bugs,
s.Changelog, s.Version, s.Manifest, s.Download, s.Background,
s.PrimaryTokenAttribute, s.Availability, s.Socket, s.Protected, s.Exclusive,
s.PersistentStorage, s.Locked, s.Owned, s.HasStorage}
_, err := tx.Exec(data.query, args...)
res, err := tx.Exec(data.query, args...)
if err != nil {
return err
}
return s.InsertObjects(tx)
rowsAffected, err := res.RowsAffected()
if rowsAffected != 0 {
err = s.InsertObjects(tx)
if err != nil {
return err
}
}
dataCopy := *data
s.ConnectGameQuery(&dataCopy)
return s.ConnectGame(tx, &dataCopy)
}
func (s *System) ConnectGameCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, s.ID}
_, err := tx.ExecContext(ctx, data.query, args...)
return err
}
func (s *System) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
@@ -109,15 +150,28 @@ func (s *System) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[stri
return ErrNoQuery
}
args := []any{data.id, s.ID, s.Title, s.Description, s.URL, s.License, s.Bugs,
setupID := sql.NullString{String: data.id, Valid: strings.EqualFold(data.fieldName, "setup_id")}
args := []any{setupID, s.ID, s.Title, s.Description, s.URL, s.License, s.Bugs,
s.Changelog, s.Version, s.Manifest, s.Download, s.Background,
s.PrimaryTokenAttribute, s.Availability, s.Socket, s.Protected, s.Exclusive,
s.PersistentStorage, s.Locked, s.Owned, s.HasStorage}
_, err := tx.ExecContext(ctx, data.query, args...)
res, err := tx.ExecContext(ctx, data.query, args...)
if err != nil {
return err
}
return s.InsertObjects(tx)
rowsAffected, err := res.RowsAffected()
if rowsAffected != 0 {
err = s.InsertObjects(tx)
if err != nil {
return err
}
}
dataCopy := *data
s.ConnectGameQuery(&dataCopy)
return s.ConnectGameCtx(ctx, tx, &dataCopy)
}

View File

@@ -1,5 +1,15 @@
package db
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/jmoiron/sqlx"
"golang.org/x/sync/errgroup"
)
type Token struct {
ID uint
@@ -16,16 +26,76 @@ type Token struct {
Alpha int
Width float64
Height float64
Ring Ring
Sight TokenSight
Texture TokenTexture
Ring *Ring
Sight *TokenSight
Texture *TokenTexture
Bar1 TokenBar
Bar2 TokenBar
Light Light
Light *Light
Occludable TokenOccludable
TurnMarker TokenTurnMarker
}
func (t *Token) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO token (%s, name, actor_link_ append_number, prepend_adjective, lock_rotation, random_img, display_name,
display_bars, disposition, rotation, alpha, width, height)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
RETURNING id`, data.fieldName)
}
func (t *Token) InsertObjects(tx *sqlx.Tx) error {
group, ctx := errgroup.WithContext(context.Background())
relId := InsertId[uint]{id: t.ID, fieldName: "token_id"}
InsertWithCtxParallel(group, ctx, tx, t.Ring, relId)
InsertWithCtxParallel(group, ctx, tx, t.Sight, relId)
InsertWithCtxParallel(group, ctx, tx, t.Texture, relId)
InsertWithCtxParallel(group, ctx, tx, t.Bar1, InsertId[uint]{id: t.ID, fieldName: "token_id", tableName: "token_bar_1"})
InsertWithCtxParallel(group, ctx, tx, t.Bar1, InsertId[uint]{id: t.ID, fieldName: "token_id", tableName: "token_bar_2"})
InsertWithCtxParallel(group, ctx, tx, t.Light, relId)
InsertWithCtxParallel(group, ctx, tx, t.Occludable, relId)
InsertWithCtxParallel(group, ctx, tx, t.TurnMarker, relId)
err := group.Wait()
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
return nil
}
func (t *Token) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Name, t.ActorLink, t.AppendNumber, t.PrependAdjective, t.LockRotation, t.RandomImg,
t.DisplayName, t.DisplayBars, t.Disposition, t.Rotation, t.Alpha, t.Width, t.Height}
err := tx.QueryRowx(data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return t.InsertObjects(tx)
}
func (t *Token) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Name, t.ActorLink, t.AppendNumber, t.PrependAdjective, t.LockRotation, t.RandomImg,
t.DisplayName, t.DisplayBars, t.Disposition, t.Rotation, t.Alpha, t.Width, t.Height}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return t.InsertObjects(tx)
}
type TokenTexture struct {
ID uint
@@ -42,6 +112,43 @@ type TokenTexture struct {
AlphaThreshold float64
}
func (t *TokenTexture) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO token_texture (%s, src, fit, tint, scale_x, scale_y, offset_x, offset_y, rotation, anchor_x, anchor_y, alpha_threshold)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
RETURNING id`, data.fieldName)
}
func (t *TokenTexture) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Src, t.Fit, t.Tint, t.ScaleX, t.ScaleY, t.OffsetX, t.OffsetY, t.Rotation, t.AnchorX, t.AnchorY, t.AlphaThreshold}
err := tx.QueryRowx(data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}
func (t *TokenTexture) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Src, t.Fit, t.Tint, t.ScaleX, t.ScaleY, t.OffsetX, t.OffsetY, t.Rotation, t.AnchorX, t.AnchorY, t.AlphaThreshold}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}
type TokenSight struct {
ID uint
@@ -54,18 +161,129 @@ type TokenSight struct {
Enabled bool
}
func (t *TokenSight) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO token_sight (%s, color, vision_mode, range_, angle, attenuation, brightness, enabled)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING id`, data.fieldName)
}
func (t *TokenSight) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Color, t.VisionMode, t.Range, t.Angle, t.Attenuation, t.Brightness, t.Enabled}
err := tx.QueryRowx(data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}
func (t *TokenSight) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Color, t.VisionMode, t.Range, t.Angle, t.Attenuation, t.Brightness, t.Enabled}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}
type TokenBar struct {
ID uint
Attribute string
}
func (t TokenBar) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO %s (%s, attribute)
VALUES ($1, $2)
RETURNING id`, data.tableName, data.fieldName)
}
func (t TokenBar) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Attribute}
err := tx.QueryRowx(data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}
func (t TokenBar) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Attribute}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}
type TokenOccludable struct {
ID uint
Radius int
}
func (t TokenOccludable) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO token_occludable (%s, radius)
VALUES ($1, $2)
RETURNING id`, data.fieldName)
}
func (t TokenOccludable) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Radius}
err := tx.QueryRowx(data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}
func (t TokenOccludable) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Radius}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}
type TokenTurnMarker struct {
ID uint
@@ -74,3 +292,40 @@ type TokenTurnMarker struct {
Src string
Disposition bool
}
func (t TokenTurnMarker) Query(data *InsertId[uint]) {
data.query = fmt.Sprintf(`
INSERT INTO token_turn_maker (%s, mode, animation, src, disposition)
VALUES ($1, $2, $3, $4, $5)
RETURNING id`, data.fieldName)
}
func (t TokenTurnMarker) Insert(tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Mode, t.Animation, t.Src, t.Disposition}
err := tx.QueryRowx(data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}
func (t TokenTurnMarker) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[uint]) error {
if data.query == "" {
return ErrNoQuery
}
args := []any{data.id, t.Mode, t.Animation, t.Src, t.Disposition}
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&t.ID)
if err != nil {
return err
}
return nil
}

View File

@@ -7,6 +7,7 @@ import (
"time"
"github.com/jmoiron/sqlx"
"github.com/mattn/go-sqlite3"
"golang.org/x/sync/errgroup"
)
@@ -172,3 +173,14 @@ func DeleteAllSeq(db *sqlx.DB) error {
return nil
}
func IsErrUniqueConstraint(err error) {
if sqliteErr, ok := err.(sqlite3.Error); ok {
// SQLITE_CONSTRAINT_UNIQUE (extended code 2067)
// or SQLITE_CONSTRAINT (basic code 19)
if sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique ||
sqliteErr.Code == sqlite3.ErrConstraint {
fmt.Println("Record already exists")
}
}
}

View File

@@ -48,10 +48,14 @@ type World struct {
func (w *World) Query(data *InsertId[string]) {
data.query = fmt.Sprintf(`
INSERT INTO world (%s, id, title, description, version, system, background, join_theme,
INSERT INTO world (%[1]s, id, title, description, version, system, background, join_theme,
core_version, system_version, last_played, playtime, availability, next_session, socket,
protected, exclusive_, persistent_storage, locked, owned, has_storage)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)`,
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)
ON CONFLICT(id) DO UPDATE SET
%[1]s = EXCLUDED.%[1]s,
updated_at = datetime('now')
RETURNING (created_at == updated_at) AS was_inserted`,
data.fieldName)
}
@@ -92,13 +96,17 @@ func (w *World) Insert(tx *sqlx.Tx, data *InsertId[string]) error {
w.CoreVersion, w.SystemVersion, w.LastPlayed, w.Playtime, w.Availability, w.NextSession, w.Socket,
w.Protected, w.Exclusive, w.PersistentStorage, w.Locked, w.Owned, w.HasStorage}
_, err := tx.Exec(data.query, args...)
var isInserted bool
err := tx.QueryRowx(data.query, args...).Scan(&isInserted)
if err != nil {
return err
}
if isInserted {
return w.InsertObjects(tx)
}
return nil
}
func (w *World) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[string]) error {
if data.query == "" {
@@ -109,10 +117,14 @@ func (w *World) InsertCtx(ctx context.Context, tx *sqlx.Tx, data *InsertId[strin
w.CoreVersion, w.SystemVersion, w.LastPlayed, w.Playtime, w.Availability, w.NextSession, w.Socket,
w.Protected, w.Exclusive, w.PersistentStorage, w.Locked, w.Owned, w.HasStorage}
_, err := tx.ExecContext(ctx, data.query, args...)
var isInserted bool
err := tx.QueryRowxContext(ctx, data.query, args...).Scan(&isInserted)
if err != nil {
return err
}
if isInserted {
return w.InsertObjects(tx)
}
return nil
}

View File

@@ -18,24 +18,28 @@ type Actor struct {
// ActorsEffects []any `json:"effects"`
}
func (a *Actor) ToDB(dest *db.Actor) bool {
func (a *Actor) ToDB(dest **db.Actor) bool {
if dest == nil {
return false
}
dest.Img = a.Img
dest.Name = a.Name
dest.Type = a.Type
dest.Folder = a.Folder
dest.Sort = a.Sort
dest.ID = a.ID
actor := &db.Actor{
Img: a.Img,
Name: a.Name,
Type: a.Type,
Folder: a.Folder,
Sort: a.Sort,
ID: a.ID,
}
a.PrototypeToken.ToDB(&dest.PrototypeToken)
a.Stats.ToDB(&dest.Stats)
a.PrototypeToken.ToDB(&actor.PrototypeToken)
a.Stats.ToDB(&actor.Stats)
OwnershipToDB(&dest.Ownership, a.Ownership)
OwnershipToDB(&actor.Ownership, a.Ownership)
CopySliceToDB(&dest.Items, a.Items)
CopySliceToDB(&actor.Items, a.Items)
*dest = actor
return true
}

View File

@@ -13,7 +13,7 @@ type CardDeck struct {
Rotation int `json:"rotation"`
DisplayCount bool `json:"displayCount"`
Stats Stats `json:"_stats"`
Ownership Ownership `json:"ownership"`
Ownership map[string]int `json:"ownership,omitempty"`
Folder string `json:"folder"`
Sort int `json:"sort"`
ID string `json:"_id"`
@@ -41,8 +41,8 @@ func (c *CardDeck) ToDB(dest **db.CardDeck) bool {
}
c.Stats.ToDB(&cardDeck.Stats)
c.Ownership.ToDB(&cardDeck.Ownership)
OwnershipToDB(&cardDeck.Ownership, c.Ownership)
CopySliceToDB(&cardDeck.Cards, c.Cards)
*dest = cardDeck

View File

@@ -1,6 +1,7 @@
package json
import (
"encoding/json"
"sync"
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/temp_models/db"
@@ -40,6 +41,19 @@ type Game struct {
// Template Template `json:"template"`
}
func ParseGame(data []byte) (*Game, error) {
var modelGame []Game
err := json.Unmarshal(data, &modelGame)
if err != nil {
return nil, err
}
if len(modelGame) > 1 {
return nil, ErrorSetupMoreThanOne
}
return &modelGame[0], nil
}
func (g *Game) ToDB(dest *db.Game) bool {
dest.UserID = g.UserID
dest.DemoMode = g.DemoMode

View File

@@ -39,6 +39,8 @@ func (j *JournalPage) ToDB(dest **db.JournalPage) bool {
OwnershipToDB(&journalPage.Ownership, j.Ownership)
*dest = journalPage
return true
}

View File

@@ -20,27 +20,31 @@ type Light struct {
Color string `json:"color"`
}
func (l *Light) ToDB(dest *db.Light) bool {
func (l *Light) ToDB(dest **db.Light) bool {
if dest == nil {
return false
}
dest.Alpha = l.Alpha
dest.Angle = l.Angle
dest.Bright = l.Bright
dest.Coloration = l.Coloration
dest.Dim = l.Dim
dest.Attenuation = l.Attenuation
dest.Luminosity = l.Luminosity
dest.Saturation = l.Saturation
dest.Contrast = l.Contrast
dest.Shadows = l.Shadows
dest.Negative = l.Negative
dest.Priority = l.Priority
dest.Color = l.Color
light := &db.Light{
Alpha: l.Alpha,
Angle: l.Angle,
Bright: l.Bright,
Coloration: l.Coloration,
Dim: l.Dim,
Attenuation: l.Attenuation,
Luminosity: l.Luminosity,
Saturation: l.Saturation,
Contrast: l.Contrast,
Shadows: l.Shadows,
Negative: l.Negative,
Priority: l.Priority,
Color: l.Color,
}
l.LightAnimation.ToDB(&dest.LightAnimation)
l.LightDarkness.ToDB(&dest.LightDarkness)
l.LightAnimation.ToDB(&light.LightAnimation)
l.LightDarkness.ToDB(&light.LightDarkness)
*dest = light
return true
}

View File

@@ -36,7 +36,7 @@ func (p *Pack) ToDB(dest **db.Pack) bool {
System: p.System,
PackageType: p.PackageType,
PackageName: p.PackageName,
Key: p.Id,
ID: p.Id,
}
p.Ownership.ToDB(&pack.Ownership)

View File

@@ -45,6 +45,8 @@ func (p *Playlist) ToDB(dest **db.Playlist) bool {
CopySliceToDB(&playlist.Sounds, p.Sounds)
*dest = playlist
return true
}

View File

@@ -9,15 +9,20 @@ type Ring struct {
Subject Subject `json:"subject"`
}
func (r *Ring) ToDB(dest *db.Ring) bool {
func (r *Ring) ToDB(dest **db.Ring) bool {
if dest == nil {
return false
}
dest.Enabled = r.Enabled
dest.Effects = r.Effects
r.RingColors.ToDB(&dest.RingColors)
r.Subject.ToDB(&dest.Subject)
ring := &db.Ring{
Enabled: r.Enabled,
Effects: r.Effects,
}
r.RingColors.ToDB(&ring.RingColors)
r.Subject.ToDB(&ring.Subject)
*dest = ring
return true
}

View File

@@ -41,6 +41,8 @@ func (t *Table) ToDB(dest **db.Table) bool {
CopySliceToDB(&table.Results, t.Results)
*dest = table
return true
}

View File

@@ -29,33 +29,37 @@ type Token struct {
// DetectionModes []any `json:"detectionModes"`
}
func (t *Token) ToDB(dest *db.Token) bool {
func (t *Token) ToDB(dest **db.Token) bool {
if dest == nil {
return false
}
dest.DisplayName = t.DisplayName
dest.DisplayBars = t.DisplayBars
dest.Disposition = t.Disposition
dest.Name = t.Name
dest.ActorLink = t.ActorLink
dest.AppendNumber = t.AppendNumber
dest.PrependAdjective = t.PrependAdjective
dest.Width = t.Width
dest.Height = t.Height
dest.LockRotation = t.LockRotation
dest.Rotation = t.Rotation
dest.Alpha = t.Alpha
dest.RandomImg = t.RandomImg
token := &db.Token{
DisplayName: t.DisplayName,
DisplayBars: t.DisplayBars,
Disposition: t.Disposition,
Name: t.Name,
ActorLink: t.ActorLink,
AppendNumber: t.AppendNumber,
PrependAdjective: t.PrependAdjective,
Width: t.Width,
Height: t.Height,
LockRotation: t.LockRotation,
Rotation: t.Rotation,
Alpha: t.Alpha,
RandomImg: t.RandomImg,
}
t.Ring.ToDB(&dest.Ring)
t.Sight.ToDB(&dest.Sight)
t.Texture.ToDB(&dest.Texture)
t.Bar1.ToDB(&dest.Bar1)
t.Bar2.ToDB(&dest.Bar2)
t.Light.ToDB(&dest.Light)
t.Occludable.ToDB(&dest.Occludable)
t.TurnMarker.ToDB(&dest.TurnMarker)
t.Ring.ToDB(&token.Ring)
t.Sight.ToDB(&token.Sight)
t.Texture.ToDB(&token.Texture)
t.Bar1.ToDB(&token.Bar1)
t.Bar2.ToDB(&token.Bar2)
t.Light.ToDB(&token.Light)
t.Occludable.ToDB(&token.Occludable)
t.TurnMarker.ToDB(&token.TurnMarker)
*dest = token
return true
}
@@ -74,22 +78,26 @@ type TokenTexture struct {
AlphaThreshold float64 `json:"alphaThreshold"`
}
func (t *TokenTexture) ToDB(dest *db.TokenTexture) bool {
func (t *TokenTexture) ToDB(dest **db.TokenTexture) bool {
if dest == nil {
return false
}
dest.Src = t.Src
dest.ScaleX = t.ScaleX
dest.ScaleY = t.ScaleY
dest.OffsetX = t.OffsetX
dest.OffsetY = t.OffsetY
dest.Rotation = t.Rotation
dest.AnchorX = t.AnchorX
dest.AnchorY = t.AnchorY
dest.Fit = t.Fit
dest.Tint = t.Tint
dest.AlphaThreshold = t.AlphaThreshold
texture := &db.TokenTexture{
Src: t.Src,
ScaleX: t.ScaleX,
ScaleY: t.ScaleY,
OffsetX: t.OffsetX,
OffsetY: t.OffsetY,
Rotation: t.Rotation,
AnchorX: t.AnchorX,
AnchorY: t.AnchorY,
Fit: t.Fit,
Tint: t.Tint,
AlphaThreshold: t.AlphaThreshold,
}
*dest = texture
return true
}
@@ -104,18 +112,22 @@ type TokenSight struct {
Brightness float64
}
func (t *TokenSight) ToDB(dest *db.TokenSight) bool {
func (t *TokenSight) ToDB(dest **db.TokenSight) bool {
if dest == nil {
return false
}
dest.Color = t.Color
dest.Enabled = t.Enabled
dest.Range = t.Range
dest.Angle = t.Angle
dest.VisionMode = t.VisionMode
dest.Attenuation = t.Attenuation
dest.Brightness = t.Brightness
sight := &db.TokenSight{
Color: t.Color,
Enabled: t.Enabled,
Range: t.Range,
Angle: t.Angle,
VisionMode: t.VisionMode,
Attenuation: t.Attenuation,
Brightness: t.Brightness,
}
*dest = sight
return true
}

View File

@@ -20,33 +20,22 @@ func (tr *FoundryTransport) FillDBWithFoundryData() {
// return
// }
// err = tr.InitWorldsData(idState)
// if err != nil {
// tr.ReadChan.Err() <- &types.FoundryError{Direction: types.WriterCode, Err: err, Type: types.DbCode}
// return
// }
err = tr.InitWorldsData()
if err != nil {
tr.ReadChan.Err() <- &types.FoundryError{Direction: types.WriterCode, Err: err, Type: types.DbCode}
return
}
}
func (tr *FoundryTransport) InitSetupData() error {
db.DeleteAll(tr.DB)
db.DeleteAllSeq(tr.DB)
for k := range requests.PathToSetupState {
err := tr.InsertJsonDataToDB(k)
if err != nil {
return err
}
}
return nil
return tr.InsertSetupToDB()
}
func (tr *FoundryTransport) InsertJsonDataToDB(statePath string) error {
_, ok1 := requests.PathToSetupState[statePath]
_, ok2 := requests.PathToWorldState[statePath]
if !ok1 && !ok2 {
return ErrorStateTypeNotExist
}
msgJson, err := tr.GetJsonData(statePath)
func (tr *FoundryTransport) InsertSetupToDB() error {
msgJson, err := tr.GetJsonDataByType(requests.SetupPath)
if err != nil {
return err
}
@@ -67,35 +56,49 @@ func (tr *FoundryTransport) InsertJsonDataToDB(statePath string) error {
return nil
}
// func (tr *FoundryTransport) InitWorldsData(idState int64) error {
// worlds, err := tr.Models.FoundryState.GetWorlds(idState)
// if err != nil {
// return err
// }
// tr.Logger.Debug("Worlds", "len", len(worlds))
func (tr *FoundryTransport) InitWorldsData() error {
worlds := []string{"kingmaker"} //TODO: get world name from database
// for i := range worlds {
// worldName := worlds[i].TextId
// tr.InitWorldData(worldName)
// _, err = tr.Http.PostReturnToSetup()
// if err != nil {
// return err
// }
// }
// return nil
// }
for i := range worlds {
worldName := worlds[i]
tr.InitWorldData(worldName)
_, err := tr.Http.PostReturnToSetup()
if err != nil {
return err
}
}
return nil
}
// func (tr *FoundryTransport) InitWorldData(worldName string) error {
// tr.Logger.Debug("World name", "name", worldName)
// err := tr.LaunchWorld(worldName)
// if err != nil {
// return err
// }
// for k := range requests.PathToWorldState {
// err := tr.InsertJsonDataToDB(k)
// if err != nil {
// return err
// }
// }
// return nil
// }
func (tr *FoundryTransport) InitWorldData(worldName string) error {
tr.Logger.Debug("World name", "name", worldName)
err := tr.LaunchWorld(worldName)
if err != nil {
return err
}
return tr.InsertGameToDB()
}
func (tr *FoundryTransport) InsertGameToDB() error {
err := tr.ConnectToWorld()
if err != nil {
return err
}
msgJson, err := tr.GetJsonData("world")
if err != nil {
return err
}
tr.Logger.Info("Game data received")
gameJson, err := json.ParseGame(msgJson)
if err != nil {
return err
}
var foundryStateDb db.Game
gameJson.ToDB(&foundryStateDb)
return foundryStateDb.Insert(tr.DB)
}

View File

@@ -8,4 +8,6 @@ var (
ErrorTimeout = errors.New("Answer has not been received after timeout")
ErrorStateTypeNotExist = errors.New("State type does not exists")
ErrorAuthPassWrong = errors.New("Authentication password is wrong")
ErrorChannelIsClosed = errors.New("Channel has been closed")
ErrorUserIsNotConnected = errors.New("User is not connected")
)

View File

@@ -17,6 +17,7 @@ type FoundryTransport struct {
ChanMutex sync.Mutex
ReadChan types.ReadChannels
ExchangeChan types.ExchangeChannels
LoggedInChan chan bool
Http *requests.FoundryHttpRequest
ReconnectTimeout time.Duration

View File

@@ -31,13 +31,7 @@ func (tr *FoundryTransport) InitWebSocketConnection() error {
dialer := websocket.DefaultDialer
dialer.ReadBufferSize = 128 * 1024 * 1024
dialer.WriteBufferSize = 128 * 1024 * 1024
// dialer.Jar = tr.Http.Jar
// ur, err := url.Parse(fmt.Sprintf("http://%s", tr.Http.Host))
// if err != nil {
// return err
// }
// fmt.Printf("TEST:%v:%v\n", u.String(), dialer.Jar.Cookies(&u))
wsConn, resp, err := dialer.Dial(u.String(), wsHeader)
if err != nil {
return err
@@ -47,8 +41,6 @@ func (tr *FoundryTransport) InitWebSocketConnection() error {
for i := range cookies {
fmt.Printf("TEST%d: %v\n", i, cookies[i])
}
// fmt.Printf("TEST1: %v\n")
// fmt.Printf("TEST2: %v\n", wsHeader)
tr.WsConn = wsConn
tr.CurrWsId = 0
@@ -118,19 +110,47 @@ func (tr *FoundryTransport) ListenWebSocket() {
}
}
func (tr *FoundryTransport) ConnectToWorld() error {
err := tr.LogInToWorld()
if err != nil {
return err
}
tr.Logger.Info("World is started. Succesfully logged into world")
tr.LoggedInChan = make(chan bool)
close(tr.ReadChan.Reconnect())
val, ok := <-tr.LoggedInChan
if !ok {
return ErrorChannelIsClosed
}
if !val {
return ErrorUserIsNotConnected
}
return nil
}
func (tr *FoundryTransport) SendOnlyCodeRequest(code string) error {
tr.Logger.Debug("WS: Data has been send\n", "msg", types.CodesRespToReq[code])
return tr.WsConn.WriteMessage(websocket.TextMessage, []byte(types.CodesRespToReq[code]))
}
func (tr *FoundryTransport) GetJsonData(stateType string) ([]byte, error) {
func (tr *FoundryTransport) GetJsonDataByType(stateType string) ([]byte, error) {
msg := types.NewWsMessageByPage(stateType, tr.CurrWsId)
tr.CurrWsId++
return tr.HandleWebsocketRequest(msg)
}
func (tr *FoundryTransport) GetJsonData(msg string) ([]byte, error) {
wsMsg := types.NewWsMessage(msg, tr.CurrWsId)
tr.CurrWsId++
return tr.HandleWebsocketRequest(wsMsg)
}
func (tr *FoundryTransport) CloseWebSocketConn() error {
tr.Logger.Debug("Websocket has been closed")
return tr.WsConn.Close()