Skip to content

Commit a03bf37

Browse files
authored
Merge branch 'dev' into dev
2 parents 07c3765 + e7f91cc commit a03bf37

File tree

531 files changed

+4741
-25733
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

531 files changed

+4741
-25733
lines changed

.github/workflows/linux.yml

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
if: "!contains(github.event.head_commit.message, 'ci skip')"
1919

2020
steps:
21-
- uses: actions/checkout@v2
21+
- uses: actions/checkout@v4
2222

2323
- name: Checkout submodules
2424
run: |
@@ -28,32 +28,27 @@ jobs:
2828
# Install dependencies
2929
- name: Update apt repositories
3030
run: sudo apt-get update
31-
32-
- name: Install GCC12
33-
shell: bash
34-
run: |
35-
sudo apt update
36-
sudo apt install gcc-12 g++-12
37-
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 110 --slave /usr/bin/g++ g++ /usr/bin/g++-12 --slave /usr/bin/gcov gcov /usr/bin/gcov-12
38-
31+
3932
# Install xmake
4033
- name: Setup xmake
4134
uses: xmake-io/github-action-setup-xmake@v1
4235
with:
43-
xmake-version: '2.9.3'
36+
xmake-version: '2.9.5'
4437

4538
# Update xmake repository (in order to have the file that will be cached)
4639
- name: Update xmake repository
4740
run: xmake repo --update
4841

4942
# Setup compilation mode and install project dependencies
43+
# (continue-on-error + timeout is a temporary solution until sentry-native is fixed; shouldn't affect the building step)
5044
- name: Configure xmake and install dependencies
51-
run: xmake config --arch=${{ matrix.arch }} --mode=${{ matrix.mode }} --yes
45+
continue-on-error: true
46+
run: timeout 15m xmake config --arch=${{ matrix.arch }} --mode=${{ matrix.mode }} --yes
5247

53-
# Build the game
48+
# Build the server
5449
- name: Build
55-
run: xmake
56-
50+
run: xmake -y
51+
5752
# Create install
5853
#- name: Install
5954
# run: xmake install -o packaged
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
name: Playable Skyrim Together Build
2+
3+
on:
4+
workflow_dispatch:
5+
schedule:
6+
# Every Friday at 1:00 p.m. UTC
7+
- cron: '0 13 * * 5'
8+
push:
9+
branches:
10+
- master
11+
tags:
12+
- 'v[0-9]+.[0-9]+.[0-9]+'
13+
14+
jobs:
15+
build:
16+
strategy:
17+
matrix:
18+
os: [windows-latest]
19+
arch: [x64]
20+
mode: [release]
21+
22+
runs-on: ${{ matrix.os }}
23+
24+
steps:
25+
- uses: actions/checkout@v4
26+
with:
27+
# We need full history in order to create a build version string (BuildInfo.h)
28+
fetch-depth: 0
29+
30+
- name: Checkout submodules
31+
run: |
32+
git submodule sync --recursive
33+
git submodule update --init --force --recursive --depth=1
34+
35+
- name: Cache xmake dependencies
36+
uses: actions/cache@v4
37+
with:
38+
path: ~/AppData/Local/.xmake/packages
39+
key: ${{ runner.os }}-xmake-${{ hashFiles('**/xmake.lua') }}
40+
41+
# Install xmake
42+
- name: Setup xmake
43+
uses: xmake-io/github-action-setup-xmake@v1
44+
with:
45+
xmake-version: 2.9.5
46+
actions-cache-folder: '.xmake-cache' # This doesn't cache dependencies, only xmake itself
47+
actions-cache-key: ${{ matrix.os }}
48+
49+
- name: Configure xmake and install dependencies
50+
run: xmake config --arch=${{ matrix.arch }} --mode=${{ matrix.mode }} --yes -vD
51+
52+
# Build the game
53+
- name: Build with xmake
54+
run: xmake -y
55+
56+
# Create distrib
57+
- name: Output STR binaries via xmake
58+
run: xmake install -o distrib
59+
60+
# Building the Together UI
61+
- name: Setup pnpm
62+
uses: pnpm/action-setup@v4
63+
with:
64+
version: 9
65+
66+
- name: Setup Node
67+
uses: actions/setup-node@v4
68+
with:
69+
node-version: lts/iron
70+
cache-dependency-path: Code/skyrim_ui/pnpm-lock.yaml
71+
cache: 'pnpm'
72+
73+
- name: Build the UI
74+
run: |
75+
pnpm --prefix Code/skyrim_ui/ install
76+
pnpm --prefix Code/skyrim_ui/ deploy:production
77+
78+
# Package everything, organize directories
79+
80+
- name: Package binaries and assets
81+
run: |
82+
mkdir -p str-build/SkyrimTogetherReborn
83+
mv build/windows/${{ matrix.arch }}/${{ matrix.mode }}/* str-build/SkyrimTogetherReborn
84+
cp -Force -Recurse distrib/bin/* str-build/SkyrimTogetherReborn
85+
cp -r Code/skyrim_ui/dist/UI str-build/SkyrimTogetherReborn
86+
cp -r GameFiles/Skyrim/* str-build/
87+
88+
- name: Remove unnecessary build files
89+
run: rm str-build/SkyrimTogetherReborn/*.pdb, str-build/SkyrimTogetherReborn/*.lib
90+
91+
# Upload artifact
92+
93+
- name: Store version string
94+
run: echo "STR_VERSION=$(git describe --tags)" >> $env:GITHUB_ENV
95+
96+
- name: Upload playable build
97+
uses: actions/upload-artifact@v4
98+
with:
99+
name: Skyrim Together Build (${{ env.STR_VERSION }})
100+
path: str-build/

.github/workflows/windows.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
- name: Setup xmake
3131
uses: xmake-io/github-action-setup-xmake@v1
3232
with:
33-
xmake-version: '2.9.3'
33+
xmake-version: '2.9.5'
3434

3535
# Install node
3636
#- name: Setup nodejs

Code/client/CrashHandler.cpp

Lines changed: 105 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <BranchInfo.h>
12
#include "CrashHandler.h"
23
#include <DbgHelp.h>
34
#include <Windows.h>
@@ -22,58 +23,120 @@ std::string SerializeTimePoint(const time_point& time, const std::string& format
2223

2324
LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
2425
{
25-
static int alreadycrashed = 0;
26+
static int alreadyCrashed = 0;
27+
auto retval = EXCEPTION_CONTINUE_SEARCH;
2628

27-
if (pExceptionInfo->ExceptionRecord->ExceptionCode == 0xC0000005 && alreadycrashed++ == 0)
28-
{
29-
spdlog::error("Crash occurred!");
30-
MINIDUMP_EXCEPTION_INFORMATION M;
31-
char dumpPath[MAX_PATH];
32-
33-
M.ThreadId = GetCurrentThreadId();
34-
M.ExceptionPointers = pExceptionInfo;
35-
M.ClientPointers = 0;
36-
37-
std::ostringstream oss;
38-
oss << "crash_" << SerializeTimePoint(std::chrono::system_clock::now(), "UTC_%Y-%m-%d_%H-%M-%S") << ".dmp";
39-
40-
GetModuleFileNameA(NULL, dumpPath, sizeof(dumpPath));
41-
std::filesystem::path modulePath(dumpPath);
42-
auto subPath = modulePath.parent_path();
43-
44-
CrashHandler::RemovePreviousDump(subPath);
45-
46-
subPath /= oss.str();
47-
48-
auto hDumpFile = CreateFileA(subPath.string().c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
49-
50-
// baseline settings from https://stackoverflow.com/a/63123214/5273909
51-
auto dumpSettings = MiniDumpWithDataSegs | MiniDumpWithProcessThreadData | MiniDumpWithHandleData | MiniDumpWithThreadInfo |
52-
/*
53-
//MiniDumpWithPrivateReadWriteMemory | // this one gens bad dump
54-
MiniDumpWithUnloadedModules |
55-
MiniDumpWithFullMemoryInfo |
56-
MiniDumpWithTokenInformation |
57-
MiniDumpWithPrivateWriteCopyMemory |
58-
*/
59-
0;
29+
// Serialize
30+
static std::mutex singleThreaded;
31+
const std::lock_guard lock{singleThreaded};
6032

61-
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, (MINIDUMP_TYPE)dumpSettings, (pExceptionInfo) ? &M : NULL, NULL, NULL);
62-
63-
CloseHandle(hDumpFile);
33+
// Check for severe, not continuable and not software-originated exception
34+
if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
35+
alreadyCrashed++ == 0)
36+
{
37+
spdlog::critical (__FUNCTION__ ": crash occurred!");
38+
39+
spdlog::error(__FUNCTION__ ": exception code is {:x}, at address {}, flags {:x} ",
40+
pExceptionInfo->ExceptionRecord->ExceptionCode,
41+
pExceptionInfo->ExceptionRecord->ExceptionAddress,
42+
pExceptionInfo->ExceptionRecord->ExceptionFlags);
43+
44+
#if (IS_MASTER)
45+
volatile static bool bMiniDump = false;
46+
#else
47+
volatile static bool bMiniDump = true;
48+
#endif
49+
if (bMiniDump)
50+
{
51+
HANDLE hDumpFile = NULL;
52+
try
53+
{
54+
MINIDUMP_EXCEPTION_INFORMATION M;
55+
char dumpPath[MAX_PATH];
56+
57+
M.ThreadId = GetCurrentThreadId();
58+
M.ExceptionPointers = pExceptionInfo;
59+
M.ClientPointers = 0;
60+
61+
std::ostringstream oss;
62+
oss << "crash_" << SerializeTimePoint(std::chrono::system_clock::now(), "UTC_%Y-%m-%d_%H-%M-%S")
63+
<< ".dmp";
64+
65+
GetModuleFileNameA(NULL, dumpPath, sizeof(dumpPath));
66+
std::filesystem::path modulePath(dumpPath);
67+
auto subPath = modulePath.parent_path();
68+
69+
CrashHandler::RemovePreviousDump(subPath);
70+
71+
subPath /= oss.str();
72+
73+
hDumpFile = CreateFileA(subPath.string().c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
74+
FILE_ATTRIBUTE_NORMAL, NULL);
75+
76+
// baseline settings from https://stackoverflow.com/a/63123214/5273909
77+
auto dumpSettings = MiniDumpWithDataSegs | MiniDumpWithProcessThreadData | MiniDumpWithHandleData |
78+
MiniDumpWithThreadInfo |
79+
/*
80+
//MiniDumpWithPrivateReadWriteMemory | // this one gens bad dump
81+
MiniDumpWithUnloadedModules |
82+
MiniDumpWithFullMemoryInfo |
83+
MiniDumpWithTokenInformation |
84+
MiniDumpWithPrivateWriteCopyMemory |
85+
*/
86+
0;
87+
88+
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, (MINIDUMP_TYPE)dumpSettings,
89+
(pExceptionInfo) ? &M : NULL, NULL, NULL);
90+
}
91+
catch (...) // Mini-dump is best effort only.
92+
{
93+
}
94+
95+
if (!hDumpFile)
96+
spdlog::critical(__FUNCTION__ ": coredump may have failed.");
97+
else
98+
{
99+
CloseHandle(hDumpFile);
100+
spdlog::critical(__FUNCTION__ ": coredump created -> flush logs.");
101+
}
102+
}
64103

65-
spdlog::error("Coredump created -> flush logs.");
66104
spdlog::default_logger()->flush();
67105

68-
return EXCEPTION_EXECUTE_HANDLER;
69-
}
106+
// Something in STR breaks top-level unhandled exception filters.
107+
// The Win API for them is pretty clunky (non-atomic, not chainable),
108+
// but they can do some important things. If someone actually set one
109+
// they probably meant it; make sure it actually runs.
110+
// This will make more CrashLogger mods work with STR.
111+
112+
// Get the current unhandled exception filter. If it has changed
113+
// from when STR started up, invoke it here.
114+
LPTOP_LEVEL_EXCEPTION_FILTER pCurrentUnhandledExceptionFilter = SetUnhandledExceptionFilter(CrashHandler::GetOriginalUnhandledExceptionFilter());
115+
SetUnhandledExceptionFilter(pCurrentUnhandledExceptionFilter);
116+
if (pCurrentUnhandledExceptionFilter != CrashHandler::GetOriginalUnhandledExceptionFilter())
117+
{
118+
spdlog::critical(__FUNCTION__ ": UnhandledExceptionFilter() workaround triggered.");
70119

71-
return EXCEPTION_CONTINUE_SEARCH;
120+
singleThreaded.unlock(); // Might reenter, but is safe at this point.
121+
if ((*pCurrentUnhandledExceptionFilter)(pExceptionInfo) == EXCEPTION_CONTINUE_EXECUTION)
122+
retval = EXCEPTION_CONTINUE_EXECUTION;
123+
singleThreaded.lock();
124+
}
125+
}
126+
return retval;
72127
}
73128

129+
LPTOP_LEVEL_EXCEPTION_FILTER CrashHandler::m_pUnhandled;
74130
CrashHandler::CrashHandler()
75131
{
76-
AddVectoredExceptionHandler(1, &VectoredExceptionHandler);
132+
// Record the original (or as close as we can get) top-level unhandled exception handler.
133+
// We grab this so we can see if it is changed, presumably by a mod or even graphics drivers.
134+
// Something in STR breaks unhandled exception handling, so we'll fake it if necessary.
135+
// This is the only way to get the current setting, but the race is small.
136+
m_pUnhandled = SetUnhandledExceptionFilter(NULL);
137+
SetUnhandledExceptionFilter(m_pUnhandled);
138+
139+
m_handler = AddVectoredExceptionHandler(1, &VectoredExceptionHandler);
77140
}
78141

79142
CrashHandler::~CrashHandler()

Code/client/CrashHandler.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,16 @@
22

33
class CrashHandler
44
{
5-
public:
5+
PVOID m_handler;
6+
static LPTOP_LEVEL_EXCEPTION_FILTER m_pUnhandled; // For remembering "original" UnhandledExceptionFilter
7+
8+
public:
69
CrashHandler();
710
~CrashHandler();
811

912
static void RemovePreviousDump(std::filesystem::path path);
13+
static inline LPTOP_LEVEL_EXCEPTION_FILTER GetOriginalUnhandledExceptionFilter()
14+
{
15+
return m_pUnhandled;
16+
}
1017
};

Code/client/Events/ActivateEvent.h

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,6 @@ struct TESBoundObject;
99
*/
1010
struct ActivateEvent
1111
{
12-
#if TP_FALLOUT4
13-
ActivateEvent(TESObjectREFR* apObject, Actor* apActivator, TESBoundObject* apObjectToGet, int32_t aCount, bool aDefaultProcessing, bool aFromScript, bool aIsLooping, bool aActivateFlag = false)
14-
: pObject(apObject)
15-
, pActivator(apActivator)
16-
, pObjectToGet(apObjectToGet)
17-
, Count(aCount)
18-
, DefaultProcessing(aDefaultProcessing)
19-
, FromScript(aFromScript)
20-
, IsLooping(aIsLooping)
21-
, ActivateFlag(aActivateFlag)
22-
{
23-
}
24-
#elif TP_SKYRIM64
2512
ActivateEvent(TESObjectREFR* apObject, Actor* apActivator, TESBoundObject* apObjectToGet, int32_t aCount, bool aDefaultProcessing, uint8_t aUnk1, TESObjectREFR::OpenState aPreActivationOpenState, bool aActivateFlag = false)
2613
: pObject(apObject)
2714
, pActivator(apActivator)
@@ -33,20 +20,13 @@ struct ActivateEvent
3320
, ActivateFlag(aActivateFlag)
3421
{
3522
}
36-
#endif
3723

3824
TESObjectREFR* pObject;
3925
Actor* pActivator;
4026
TESBoundObject* pObjectToGet;
4127
int32_t Count;
4228
bool DefaultProcessing;
43-
#if TP_FALLOUT4
44-
bool FromScript;
45-
bool IsLooping;
46-
#elif TP_SKYRIM64
4729
uint8_t Unk1;
48-
#endif
49-
5030
TESObjectREFR::OpenState PreActivationOpenState;
5131
bool ActivateFlag;
5232
};

0 commit comments

Comments
 (0)