Skip to content

Commit 62a911f

Browse files
OmniTroidclaude
andcommitted
Add web cache feature for automatic asset downloading
Adds a web cache system that automatically downloads missing assets from the server's asset URL and caches them locally. Includes options UI for enabling/ disabling the cache, setting expiry time, viewing cache size, and clearing. Also fixes macOS build issues: - Override WrapOpenGL to skip deprecated AGL framework - Fix BASS/BASSOPUS header paths in configure.sh for macOS - Fix vexing parse in webcache.cpp Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 54afcee commit 62a911f

12 files changed

Lines changed: 519 additions & 3 deletions

CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.7.0)
1+
cmake_minimum_required(VERSION 3.16)
22

33
project(AttorneyOnline VERSION 2.11.0.0 LANGUAGES CXX C)
44

@@ -14,6 +14,13 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
1414
option(AO_BUILD_TESTS "Build test programs" ON)
1515
option(AO_ENABLE_DISCORD_RPC "Enable Discord Rich Presence" ON)
1616

17+
# Override WrapOpenGL to not require deprecated AGL framework on macOS
18+
if(APPLE AND NOT TARGET WrapOpenGL::WrapOpenGL)
19+
add_library(WrapOpenGL::WrapOpenGL INTERFACE IMPORTED)
20+
target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE "-framework OpenGL")
21+
set(WrapOpenGL_FOUND ON)
22+
endif()
23+
1724
find_package(QT NAMES Qt6)
1825
find_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets Concurrent WebSockets UiTools)
1926

@@ -91,6 +98,8 @@ qt_add_executable(Attorney_Online
9198
src/serverdata.cpp
9299
src/serverdata.h
93100
src/text_file_functions.cpp
101+
src/webcache.cpp
102+
src/webcache.h
94103
src/widgets/aooptionsdialog.cpp
95104
src/widgets/aooptionsdialog.h
96105
src/widgets/direct_connect_dialog.cpp

configure.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ get_bass() {
240240
libs/x86_64/libbass.so:./bin
241241
elif [[ "$PLATFORM" == "macos" ]]; then
242242
get_zip https://www.un4seen.com/files/bass24-osx.zip \
243-
bass.h:./lib \
243+
c/bass.h:./lib \
244244
libbass.dylib:./lib
245245
fi
246246
}
@@ -266,7 +266,7 @@ get_bassopus() {
266266
libs/x86_64/libbassopus.so:./bin
267267
elif [[ "$PLATFORM" == "macos" ]]; then
268268
get_zip https://www.un4seen.com/files/bassopus24-osx.zip \
269-
bassopus.h:./lib \
269+
c/bassopus.h:./lib \
270270
libbassopus.dylib:./lib
271271
fi
272272
}

data/ui/options_dialog.ui

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,99 @@ Use this when you have added an asset that takes precedence over another existin
908908
</item>
909909
</layout>
910910
</item>
911+
<item>
912+
<widget class="QFrame" name="webcache_divider">
913+
<property name="frameShape">
914+
<enum>QFrame::HLine</enum>
915+
</property>
916+
<property name="frameShadow">
917+
<enum>QFrame::Sunken</enum>
918+
</property>
919+
</widget>
920+
</item>
921+
<item>
922+
<widget class="QLabel" name="webcache_header_lbl">
923+
<property name="text">
924+
<string>Web Cache</string>
925+
</property>
926+
<property name="font">
927+
<font>
928+
<bold>true</bold>
929+
</font>
930+
</property>
931+
</widget>
932+
</item>
933+
<item>
934+
<layout class="QFormLayout" name="webcache_form_layout">
935+
<item row="0" column="0">
936+
<widget class="QLabel" name="webcache_enabled_lbl">
937+
<property name="toolTip">
938+
<string>If enabled, assets not found locally will be automatically downloaded from the server's asset URL and cached for future use.</string>
939+
</property>
940+
<property name="text">
941+
<string>Enable Web Cache:</string>
942+
</property>
943+
</widget>
944+
</item>
945+
<item row="0" column="1">
946+
<widget class="QCheckBox" name="webcache_enabled_cb">
947+
<property name="text">
948+
<string/>
949+
</property>
950+
</widget>
951+
</item>
952+
<item row="1" column="0">
953+
<widget class="QLabel" name="webcache_expiry_lbl">
954+
<property name="toolTip">
955+
<string>How long cached files remain valid before being re-downloaded. Set to a higher value to reduce bandwidth usage.</string>
956+
</property>
957+
<property name="text">
958+
<string>Cache Expiry:</string>
959+
</property>
960+
</widget>
961+
</item>
962+
<item row="1" column="1">
963+
<widget class="QSpinBox" name="webcache_expiry_spinbox">
964+
<property name="suffix">
965+
<string> hours</string>
966+
</property>
967+
<property name="minimum">
968+
<number>1</number>
969+
</property>
970+
<property name="maximum">
971+
<number>720</number>
972+
</property>
973+
<property name="value">
974+
<number>24</number>
975+
</property>
976+
</widget>
977+
</item>
978+
<item row="2" column="0">
979+
<widget class="QLabel" name="webcache_size_label_lbl">
980+
<property name="text">
981+
<string>Cache Size:</string>
982+
</property>
983+
</widget>
984+
</item>
985+
<item row="2" column="1">
986+
<widget class="QLabel" name="webcache_size_label">
987+
<property name="text">
988+
<string>0 MB</string>
989+
</property>
990+
</widget>
991+
</item>
992+
<item row="3" column="1">
993+
<widget class="QPushButton" name="webcache_clear">
994+
<property name="toolTip">
995+
<string>Deletes all cached files downloaded from servers.</string>
996+
</property>
997+
<property name="text">
998+
<string>Clear Web Cache</string>
999+
</property>
1000+
</widget>
1001+
</item>
1002+
</layout>
1003+
</item>
9111004
</layout>
9121005
</widget>
9131006
<widget class="QWidget" name="logging_tab">

src/aoapplication.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "lobby.h"
66
#include "networkmanager.h"
77
#include "options.h"
8+
#include "webcache.h"
89
#include "widgets/aooptionsdialog.h"
910

1011
static QtMessageHandler original_message_handler;
@@ -21,6 +22,7 @@ AOApplication::AOApplication(QObject *parent)
2122
{
2223
net_manager = new NetworkManager(this);
2324
discord = new AttorneyOnline::Discord();
25+
m_webcache = new WebCache(this);
2426

2527
asset_lookup_cache.reserve(2048);
2628

@@ -36,6 +38,11 @@ AOApplication::~AOApplication()
3638
qInstallMessageHandler(original_message_handler);
3739
}
3840

41+
WebCache *AOApplication::webcache() const
42+
{
43+
return m_webcache;
44+
}
45+
3946
bool AOApplication::is_lobby_constructed()
4047
{
4148
return w_lobby;

src/aoapplication.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class NetworkManager;
2929
class Lobby;
3030
class Courtroom;
3131
class Options;
32+
class WebCache;
3233

3334
class VPath : QString
3435
{
@@ -60,6 +61,12 @@ class AOApplication : public QObject
6061
Lobby *w_lobby = nullptr;
6162
Courtroom *w_courtroom = nullptr;
6263
AttorneyOnline::Discord *discord;
64+
WebCache *webcache() const;
65+
66+
private:
67+
WebCache *m_webcache = nullptr;
68+
69+
public:
6370

6471
QFont default_font;
6572

src/options.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,3 +794,23 @@ void Options::setRestoreWindowPositionEnabled(bool state)
794794
{
795795
config.setValue("windows/restore", state);
796796
}
797+
798+
bool Options::webcacheEnabled() const
799+
{
800+
return config.value("webcache_enabled", true).toBool();
801+
}
802+
803+
void Options::setWebcacheEnabled(bool value)
804+
{
805+
config.setValue("webcache_enabled", value);
806+
}
807+
808+
int Options::webcacheExpiryHours() const
809+
{
810+
return config.value("webcache_expiry_hours", 24).toInt();
811+
}
812+
813+
void Options::setWebcacheExpiryHours(int hours)
814+
{
815+
config.setValue("webcache_expiry_hours", hours);
816+
}

src/options.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,13 @@ class Options
281281
bool restoreWindowPositionEnabled() const;
282282
void setRestoreWindowPositionEnabled(bool state);
283283

284+
// Webcache settings
285+
bool webcacheEnabled() const;
286+
void setWebcacheEnabled(bool value);
287+
288+
int webcacheExpiryHours() const;
289+
void setWebcacheExpiryHours(int hours);
290+
284291
private:
285292
/**
286293
* @brief QSettings object for config.ini

src/path_functions.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "courtroom.h"
33
#include "file_functions.h"
44
#include "options.h"
5+
#include "webcache.h"
56

67
#include <QDir>
78
#include <QRegularExpression>
@@ -421,6 +422,20 @@ QString AOApplication::get_real_path(const VPath &vpath, const QStringList &suff
421422
}
422423
}
423424

425+
// Check webcache if local file not found
426+
if (Options::getInstance().webcacheEnabled() && !m_serverdata.get_asset_url().isEmpty())
427+
{
428+
QString cached = m_webcache->getCachedPath(vpath.toQString());
429+
if (!cached.isEmpty())
430+
{
431+
asset_lookup_cache.insert(qHash(vpath), cached);
432+
return cached;
433+
}
434+
435+
// Initiate background download for future requests
436+
m_webcache->resolveOrDownload(vpath.toQString(), suffixes);
437+
}
438+
424439
// Not found in mount paths; check if the file is remote
425440
QString remotePath = vpath.toQString();
426441
if (remotePath.startsWith("http:") || remotePath.startsWith("https:"))

0 commit comments

Comments
 (0)