Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
『GRANBLUE FANTASY: Relink』の長期開発を支え続けたテスト自動化の取り組み紹介
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Cygames, Inc.
PRO
December 18, 2024
Technology
670
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
『GRANBLUE FANTASY: Relink』の長期開発を支え続けたテスト自動化の取り組み紹介
Cygames, Inc.
PRO
December 18, 2024
More Decks by Cygames, Inc.
See All by Cygames, Inc.
【CEDEC2026】Creative Approaches to Localizing the Dialects and Unique Speech of Umamusume: Pretty Derby Characters in English
cygames
PRO
4
27k
【CEDEC2026】コードレビュー支援ツール開発から学ぶ:LLMを用いた業務システムの実践的な運用設計と誤出力対策
cygames
PRO
0
1.2k
【CEDEC2026】『ウマ娘 プリティーダービー』 英語版のキャラクターの方言や口調をローカライズするための創造的アプローチ
cygames
PRO
3
1.3k
【CEDEC2026】次世代デジタルカードゲームのサーバー設計と運用 〜『Shadowverse: Worlds Beyond』の舞台裏~
cygames
PRO
2
2.1k
【CEDEC2026】派手さと見やすさは両立できる!『Shadowverse: Worlds Beyond』エフェクト・3D背景の超進化したビジュアル設計
cygames
PRO
1
1.9k
【CEDEC2026】『Shadowverse: Worlds Beyond』続編開発におけるUIデザイン・アニメーション演出の「超進化」 ~継承と挑戦を両立するデザイン手法~
cygames
PRO
3
5.2k
【CEDEC2026】『Relink』を拡張せよ - 『GRANBLUE FANTASY: Relink - Endless Ragnarok』の開発速度と品質を守るCI運用
cygames
PRO
1
280
【CEDEC2026】『GRANBLUE FANTASY: Relink - Endless Ragnarok』のバトル制作事例 ~最高のキャラゲーを目指して~
cygames
PRO
2
470
【CEDEC2026】アートとゲームデザインをつなぐVFX設計『GRANBLUE FANTASY: Relink - Endless Ragnarok』における表現と可読性の両立
cygames
PRO
1
1.3k
Other Decks in Technology
See All in Technology
俺の仕事は AIに奪われないし、たぶんその BIも要らない
hikaruri
0
370
Deploying a Full-Stack Bun-Native Framework on Cloudflare Workers
7nohe
0
160
深夜のクラウド懺悔室 1:29:300 or 1:0:0
kazzpapa3
1
240
アプリログインとWeb認証基盤をつなぐ ASWebAuthenticationSession 作法
shimastripe
1
290
おい、エージェントを使って終わらせろ
nwiizo
0
130
2026-09-09 【sigma_ucj#1】Sigma を IaC 管理したい! / IaC for Sigma
civitaspo
0
130
The Agent Builder Loop from Daily Work to OSS
minorun365
PRO
3
160
なぜJMBC(Japan MCP Business Community)? MCPってどう活用できるの?
cdataj
0
110
銀行勘定系システムにおける開発プロセス刷新×AIによる環境モダナイゼーション / Development Process Transformation and AI-Driven Environment Modernization
muit
0
950
2026-09-10 【Snowflake World Tour Tokyo 2026】dbt Core と Snowflake で実現する多層的なデータガバナンス / Multi-Layered Data Governance Powered by dbt Core and Snowflake
civitaspo
0
370
アプリをもっと"iOSアプリっぽく"する小さな工夫 / Small Touches That Make Your App Feel More Like an iOS App
matsuji
1
800
Tab5をRubyで動くパソコンにする
kishima
2
360
Featured
See All Featured
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
400
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
700
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
The Cult of Friendly URLs
andyhume
79
7k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
The Cost Of JavaScript in 2023
addyosmani
55
10k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2.1k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.2k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
410
Making Projects Easy
brettharned
120
6.7k
So, you think you're a good person
axbom
PRO
2
2.2k
Transcript
1/92
2/92
3/92 ◆ ◆ ◆
4/92
5/92
6/92
7/92
8/92
9/92
10/92
11/92
12/92
13/92
14/92
15/92
16/92 ◆ ◆
17/92
18/92 ◆ ◆ ◆
19/92
20/92 autoplay_pipeline.exe ( golang ) Jenkins ( groovy Pipeline Script
) granblue_fantasy_relink.exe
21/92
22/92 ◆ ◆ ◆
23/92
24/92
25/92
26/92
27/92
28/92
29/92
30/92
31/92
32/92
33/92
34/92
35/92
36/92
37/92
38/92
39/92
40/92
41/92
42/92
43/92 ◆ ◆
44/92
45/92
46/92
47/92
48/92
49/92
50/92
51/92
52/92
53/92
54/92
55/92 ◆ ◆ ◆
56/92
57/92
58/92
59/92
60/92 ◆ ◆ ◆ ◆
61/92
62/92 f32 PointLightData::updateDistanceCurve() { auto retRate = 0.0f; auto distanceMin
= distanceA_; auto distanceMax = distanceB_; auto t = (cameraDistance_ - distanceMin) / (distanceMax - distanceMin); t = GET_CLAMPF(t, 0.f, 1.f); // return t; }
63/92 f32 PointLightData::updateDistanceCurve() { auto retRate = 0.0f; auto distanceMin
= distanceA_; auto distanceMax = distanceB_; // . auto denominator = (distanceMax - distanceMin); auto t = denominator <= FLT_EPSILON ? 1.f : (cameraDistance_ - distanceMin) / denominator; t = GET_CLAMPF(t, 0.f, 1.f); // return t; }
64/92
65/92 ◆ ◆ ◆ ◆
66/92 Matrix44 transform[3]; // Vector4 vertexs[16]; for (s32 i =
0, inum = std::size(vertexs); i < inum; ++i) { const div_t d = div(i, 4); VecMulMtx(vertexs[i], g_baseVertex[d.rem], transform[d.quot]); }
67/92 Matrix44 transform[4]; // Vector4 vertexs[16]; for (s32 i =
0, inum = std::size(vertexs); i < inum; ++i) { const div_t d = div(i, 4); VecMulMtx(vertexs[i], g_baseVertex[d.rem], transform[d.quot]); }
68/92 constexpr MaterialVariationID DEFAULT_MATERIAL_VARIATION_ID = 0; void hoge() { huga
= KeyData::getConstantKeyParamWithDefault(subseq.materialVariationIdList_, 0.0f, asset::DEFAULT_MATERIAL_VARIATION_ID); } template<typename KeyParam> KeyParam getConstantKeyParamWithDefault(const std::vector<Timeline::EventKeyParamData<KeyParam>>& list, f64 nowSeconds, const KeyParam& defaultValue) { // }
69/92 constexpr MaterialVariationID DEFAULT_MATERIAL_VARIATION_ID = 0; void hoge() { huga
= KeyData::getConstantKeyParamWithDefault(subseq.materialVariationIdList_, 0.0f, asset::DEFAULT_MATERIAL_VARIATION_ID); } template<typename KeyParam> KeyParam getConstantKeyParamWithDefault(const std::vector<Timeline::EventKeyParamData<KeyParam>>& list, f64 nowSeconds, const KeyParam defaultValue) { // }
70/92 SceneObject* SceneObject::clone(SceneObject* pParent, bool isRename, bool isEntity) const {
const char* pName; if (isRename != false) { auto name = mName; // pName = name.get(); } else { pName = mName.get(); } auto pNewObject = SceneObject::create(className(), pName, pParent, false); }
71/92 SceneObject* SceneObject::clone(SceneObject* pParent, bool isRename, bool isEntity) const {
SceneObject* pNewObject = nullptr; if (isRename != false) { auto name = name_; // pNewObject = SceneObject::create(className(), name.get(), pParent, false); } else { pNewObject = SceneObject::create(className(), mName.get(), pParent, false); } }
72/92
73/92
74/92
75/92
76/92 void write() { // void* address = reinterpret_cast<void*> (0x0123456789A);
// placement new MyClass* obj = new (address) MyClass(42); } void read() { // void* address = reinterpret_cast<void*> (0x0123456789A); std::cout << reinterpret_cast<MyClass*> (address)->data << std::endl; }
77/92 ================== WARNING: ThreadSanitizer: data race (pid=174) Write of size
8 at 0x0010a48bb360 by thread T11: #0 0x81119cf39 (ThreadSanitizer.sprx+0x64f39) #1 0x26670e46 in Mtx44Copy(Matrix44&, Matrix44 const&) { } #2 0x26670e46 in Matrix44::operator=(Matrix44 const&) { } #3 0x2c23d8b8 in Joint::setWorldMatrix(Matrix44 const&) { } #4 0x2c23d8b8 in JointList::addVecJointMatrix(Joint&, Vector4 const&) { } … Previous read of size 8 at 0x0010a48bb360 by thread T12: )(void*, void*) const { } … #5 0x2c23b98e in Joint::getWorldPos() const { } #6 0x2c22ce88 in ModelImpl::getWorldPos() const { } …
78/92 ================== WARNING: ThreadSanitizer: data race (pid=174) Write of size
8 at 0x0010a48bb360 by thread T11: #0 0x81119cf39 (ThreadSanitizer.sprx+0x64f39) #1 0x26670e46 in Mtx44Copy(Matrix44&, Matrix44 const&) { } #2 0x26670e46 in Matrix44::operator=(Matrix44 const&) { } #3 0x2c23d8b8 in Joint::setWorldMatrix(Matrix44 const&) { } #4 0x2c23d8b8 in JointList::addVecJointMatrix(Joint&, Vector4 const&) { } … Previous read of size 8 at 0x0010a48bb360 by thread T12: )(void*, void*) const { } … #5 0x2c23b98e in Joint::getWorldPos() const { } #6 0x2c22ce88 in ModelImpl::getWorldPos() const { } …
79/92 void Np0100::updateParameter() { Vector4 playerPos = PlayerManager::GetManualPlayerPos(); Vector4 vec
= getPos() - playerPos; f32 length = VecMag(vec); f32 lengthY = vec.y; vec.y = 0.0f; f32 lengthXZ = VecMag(vec); }
80/92 void Np0100::updateParameter() { Vector4 playerPos = PlayerManager::GetManualPlayerPosRef(); Vector4 vec
= getPos() - playerPos; f32 length = VecMag(vec); f32 lengthY = vec.y; vec.y = 0.0f; f32 lengthXZ = VecMag(vec); }
81/92 ================== WARNING: ThreadSanitizer: data race (pid=490) Write of size
8 at 0x00101a3a4000 by thread T10: #0 0x73b877da in model::bool_vector::set(unsigned long, bool) {コードの場所} #1 0x73bbfcdf in model::BoundingVolume::setForceVisible(bool) const {コードの場所} #2 0x73bfc74b in ModelImpl::updateBoundingVolume() {コードの場所} #3 0x73c24800 in auto ModelProcessingImpl::updateModelList(concurrency::JobSystem&):: ...template... const {コード の場所} #4 0x73c24800 in void concurrency::JobSystem::parallelForEach ...template... const {コードの場所} Previous write of size 8 at 0x00101a3a4000 by thread T14: #0 0x73b877bc in model::bool_vector::set(unsigned long, bool) {コードの場所} #1 0x73bbfcdf in model::BoundingVolume::setForceVisible(bool) const {コードの場所} #2 0x73bfc74b in ModelImpl::updateBoundingVolume() {コードの場所} #3 0x73c24800 in auto ModelProcessingImpl::updateModelList(concurrency::JobSystem&):: ...template... const {コード の場所} #4 0x73c24800 in void concurrency::JobSystem::parallelForEach ...template... const {コードの場所}
82/92 int main() { std::vector<u8> numbers = { 1, 2,
3 }; std::thread t1([&]() { numbers[0] = 42; //OK }); std::thread t2([&]() { numbers[1] = 84; //OK }); t1.join(); t2.join(); return 0; } int main() { std::vector<u8> numbers = { 1, 2, 3 }; std::thread t1([&]() { numbers[0] = 42; //t2 }); std::thread t2([&]() { numbers[0] = 84; //t1 }); t1.join(); t2.join(); return 0; }
83/92 int main() { std::vector<bool> flags = { true, false,
true }; std::thread t1([&]() { flags[0] = true; //NG }); std::thread t2([&]() { flags[1] = true; //NG }); t1.join(); t2.join(); return 0; }
84/92
85/92
86/92
87/92 ◆ ◆ ◆
88/92
89/92 ◆ ◆ ◆
90/92 ◆ ◆ ◆
91/92 ◆ ◆ ◆
92/92