();
118 | var lang = _ds3.Languages[_lang];
119 | foreach (var item in checkedListBoxItems.CheckedItems)
120 | {
121 | switch (item.ToString())
122 | {
123 | case "Accessory":
124 | items.AddRange(lang.Accessory.Values.Select(i => new ViewerItem("Accessory", i)));
125 | break;
126 | case "Armor":
127 | items.AddRange(lang.Armor.Values.Select(i => new ViewerItem("Armor", i)));
128 | break;
129 | case "Item":
130 | items.AddRange(lang.Item.Values.Select(i => new ViewerItem("Item", i)));
131 | break;
132 | case "Magic":
133 | items.AddRange(lang.Magic.Values.Select(i => new ViewerItem("Magic", i)));
134 | break;
135 | case "Weapon":
136 | items.AddRange(lang.Weapon.Values.Select(i => new ViewerItem("Weapon", i)));
137 | break;
138 | default:
139 | throw new NotImplementedException();
140 | }
141 | }
142 | try
143 | {
144 | listBoxItems.DataSource = items.Where(MatchesFilter).OrderBy(item => item.Item.Name).ToArray();
145 | }
146 | catch (Exception ex)
147 | {
148 | MessageBox.Show(ex.Message, "Filter error");
149 | }
150 | }
151 |
152 | void updateConversationList()
153 | {
154 | webBrowserConversation.DocumentText = "";
155 | var lang = _ds3.Languages[_lang];
156 | try
157 | {
158 | listBoxConversations.DataSource = lang.Conversations.Values.Where(MatchesFilter).ToArray();
159 | }
160 | catch (Exception ex)
161 | {
162 | MessageBox.Show(ex.Message, "Filter error");
163 | }
164 | }
165 |
166 | void updateContainerList()
167 | {
168 | webBrowserContainer.DocumentText = "";
169 | var lang = _ds3.Languages[_lang];
170 | listBoxContainerContent.DataSource = new object[0];
171 | try
172 | {
173 | listBoxContainers.DataSource = lang.Containers.Values.Where(MatchesFilter).ToArray();
174 | }
175 | catch (Exception ex)
176 | {
177 | MessageBox.Show(ex.Message, "Filter error");
178 | }
179 | }
180 |
181 | string EscapeHtml(string s)
182 | {
183 | return s.Replace("&", "&")
184 | .Replace("<", "<")
185 | .Replace(">", ">")
186 | .Replace("\"", """)
187 | .Replace("\n", "
");
188 | }
189 |
190 | void listBoxContainerContent_SelectedIndexChanged(object sender, EventArgs e)
191 | {
192 | var item = (ContainerContent) listBoxContainerContent.SelectedItem;
193 | var template = @"
194 |
195 |
198 |
199 |
200 | {0}
201 | {1}
202 | ";
203 | webBrowserContainer.DocumentText = string.Format(template,
204 | item.Id,
205 | EscapeHtml(item.Text));
206 | }
207 |
208 | void listBoxConversations_SelectedIndexChanged(object sender, EventArgs e)
209 | {
210 | var item = (Conversation) listBoxConversations.SelectedItem;
211 | var template = @"
212 |
213 |
217 |
218 |
219 | {0}
220 | {1}
221 | {{{0}}} dlc{2}
222 | ";
223 | webBrowserConversation.DocumentText = string.Format(template,
224 | item.Id,
225 | EscapeHtml(item.Text),
226 | item.Dlc);
227 | }
228 |
229 | void listBoxItems_SelectedIndexChanged(object sender, EventArgs e)
230 | {
231 | var item = (ViewerItem) listBoxItems.SelectedItem;
232 | var template = @"
233 |
234 |
238 |
239 |
240 | {0}
241 | {1}
242 | {2}
243 | {{{3}}} {{{4}}} dlc{5}
244 | ";
245 | webBrowserItem.DocumentText = string.Format(template,
246 | item,
247 | EscapeHtml(item.Item.Description),
248 | EscapeHtml(item.Item.Knowledge),
249 | item.Parent,
250 | item.Item.Id,
251 | item.Item.Dlc);
252 | }
253 |
254 | private void enableControls(bool enabled)
255 | {
256 | tabControlMain.Enabled = enabled;
257 | comboBoxLanguage.Enabled = enabled;
258 | textBoxFilter.Enabled = enabled;
259 | buttonApply.Enabled = enabled;
260 | buttonHelp.Enabled = enabled;
261 | }
262 |
263 | private bool loadData(string filename)
264 | {
265 | try
266 | {
267 | _ds3 = JSONHelper.Deserialize(File.ReadAllText(filename, new UTF8Encoding(false)));
268 | enableControls(true);
269 | }
270 | catch
271 | {
272 | enableControls(false);
273 | return false;
274 | }
275 | comboBoxLanguage.Items.AddRange(_ds3.Languages.Keys.ToArray());
276 | if (comboBoxLanguage.Items.Count > 1)
277 | comboBoxLanguage.SelectedIndex = 1; //engUS
278 | return true;
279 | }
280 |
281 | private void buttonLoadData_Click(object sender, EventArgs e)
282 | {
283 | var dialog = new OpenFileDialog
284 | {
285 | Filter = "JSON Files (*.json)|*.json",
286 | FileName = "ds3.json",
287 | InitialDirectory = AppDomain.CurrentDomain.BaseDirectory,
288 | Title = "Select JSON"
289 | };
290 | if (dialog.ShowDialog() != DialogResult.OK)
291 | return;
292 | if (loadData(dialog.FileName))
293 | MessageBox.Show("Data loaded!", "OK", MessageBoxButtons.OK, MessageBoxIcon.Information);
294 | else
295 | MessageBox.Show("Failed to load data...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
296 | }
297 |
298 | bool MatchesFilter(string text, string filter)
299 | {
300 | return _culture.CompareInfo.IndexOf(text, filter, CompareOptions.IgnoreCase) >= 0;
301 | }
302 |
303 | bool MatchesFilter(string text)
304 | {
305 | if (_filter == null)
306 | return true;
307 | return _filter.Calculate(filter => MatchesFilter(text, filter));
308 | }
309 |
310 | bool MatchesFilter(GenericItem item, string parent = "")
311 | {
312 | var builder = new StringBuilder();
313 | if (parent.Length > 0)
314 | builder.AppendFormat("{{{0}}}", parent);
315 | builder.AppendFormat("{{{0}}}", item.Id);
316 | builder.AppendFormat("dlc{0}", item.Dlc);
317 | builder.AppendLine();
318 | builder.Append(item.Name.Replace("\n", " "));
319 | builder.Append(item.Description.Replace("\n", " "));
320 | builder.Append(item.Knowledge.Replace("\n", " "));
321 | return MatchesFilter(builder.ToString());
322 | }
323 |
324 | bool MatchesFilter(ViewerItem item)
325 | {
326 | return MatchesFilter(item.Item, item.Parent);
327 | }
328 |
329 | bool MatchesFilter(Conversation conversation)
330 | {
331 | var builder = new StringBuilder();
332 | builder.AppendFormat("{{{0}}}", conversation.Id);
333 | builder.AppendFormat("dlc{0}", conversation.Dlc);
334 | builder.AppendLine();
335 | builder.Append(conversation.Text.Replace("\n", " "));
336 | return MatchesFilter(builder.ToString());
337 | }
338 |
339 | bool MatchesFilter(KeyValuePair it)
340 | {
341 | var builder = new StringBuilder();
342 | builder.AppendFormat("{{{0}}}", it.Key);
343 | builder.AppendLine();
344 | builder.Append(it.Value.Replace("\n", " "));
345 | return MatchesFilter(builder.ToString());
346 | }
347 |
348 | bool MatchesFilter(Container container)
349 | {
350 | foreach (var c in container.Content)
351 | if (MatchesFilter(c))
352 | return true;
353 | return false;
354 | }
355 |
356 | private void buttonApply_Click(object sender, EventArgs e)
357 | {
358 | try
359 | {
360 | _filter = new ExpressionParser(textBoxFilter.Text);
361 | _filter.Calculate(str => true);
362 | }
363 | catch (Exception ex)
364 | {
365 | MessageBox.Show(ex.Message, "Invalid filter!", MessageBoxButtons.OK, MessageBoxIcon.Error);
366 | return;
367 | }
368 | refreshLists();
369 | }
370 |
371 | private void buttonHelp_Click(object sender, EventArgs e)
372 | {
373 | MessageBox.Show(@"Dark Souls 3 Text Viewer
374 | This tool helps you view all in-game text of Dark Souls 3.
375 |
376 | Filters
377 | You can use filters to find relevant information. Text
378 | is compared case-insensitive and you can combine
379 | multiple filters with operators & (AND) | (OR) ~ (NOT).
380 |
381 | - Identifiers can be found with '{id}'
382 | - DLC version can be found with 'dlcN'
383 | - Item type can be found with '{type}'
384 |
385 | Operators are evaluated in the following order:
386 |
387 | 1. Parentheses
388 | 2. NOT
389 | 3. AND
390 | 4. OR
391 |
392 | Examples
393 | Filter: aldrich|deep
394 | Effect: Everything containing 'aldrich' or 'deep'
395 |
396 | Filter: god&swamp
397 | Effect: Everything containing 'god' and 'swamp'
398 |
399 | Filter: aldrich&deep|children
400 | Effect: With braces: aldrich&(deep|children)
401 |
402 | Filter: {1200}
403 | Effect: Matches text with ID 1200
404 |
405 | Filter: magic&~{Magic}
406 | Effect: All non-{Magic} items containing 'magic'", "Help");
407 | }
408 |
409 | private void linkBonfireSideChat_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
410 | {
411 | System.Diagnostics.Process.Start("http://www.bonfireside.chat");
412 | }
413 |
414 | private void buttonGraph_Click(object sender, EventArgs e)
415 | {
416 | string[] blacklist;
417 | var file = "blacklist_" + comboBoxLanguage.SelectedItem + ".txt";
418 | try
419 | {
420 | blacklist = File.ReadAllLines(file);
421 | }
422 | catch
423 | {
424 | MessageBox.Show("Could not find " + file);
425 | blacklist = null;
426 | }
427 | var analysis = new Analysis(blacklist);
428 | var items = new List();
429 | var builder = new StringBuilder();
430 | foreach (var it in listBoxItems.Items)
431 | {
432 | builder.Clear();
433 | var item = (ViewerItem) it;
434 | builder.AppendLine(item.Item.Name);
435 | builder.AppendLine(item.Item.Description);
436 | builder.AppendLine(item.Item.Knowledge);
437 | items.Add(builder.ToString().ToLower(_culture));
438 | }
439 | MessageBox.Show("Built items!");
440 | foreach (var item in items)
441 | analysis.AddText(item);
442 | MessageBox.Show("Built nodes!");
443 | analysis.Prepare();
444 | MessageBox.Show("Prepared matrix!");
445 | foreach(var item in items)
446 | analysis.ConnectText(item);
447 | MessageBox.Show("Connected items!");
448 | File.WriteAllText("graph.dot", analysis.ToDot());
449 | MessageBox.Show("Done!");
450 | }
451 |
452 | private void linkLabelCreatedBy_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
453 | {
454 | System.Diagnostics.Process.Start("https://github.com/mrexodia/DarkSouls3.TextViewer");
455 | }
456 |
457 | private void linkLabelGephi_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
458 | {
459 | System.Diagnostics.Process.Start("https://gephi.org");
460 | }
461 | }
462 |
463 | public class ContainerContent
464 | {
465 | public string Id;
466 | public string Text;
467 |
468 | public ContainerContent(string id, string text)
469 | {
470 | Id = id;
471 | Text = text;
472 | }
473 |
474 | public override string ToString()
475 | {
476 | var split = Text.Split('\n')[0].Split(' ');
477 | var quote = new StringBuilder();
478 | quote.Append(split[0]);
479 | for (var i = 1; i < split.Length && quote.Length < 20; i++)
480 | {
481 | quote.Append(' ');
482 | quote.Append(split[i]);
483 | }
484 | if (quote.Length < Text.Length && !quote.ToString().EndsWith("..."))
485 | quote.Append("...");
486 | return string.Format("{0} \"{1}\"", Id, quote);
487 | }
488 | }
489 |
490 | public class ViewerItem
491 | {
492 | public string Parent;
493 | public GenericItem Item;
494 |
495 | public ViewerItem(string parent, GenericItem item)
496 | {
497 | Parent = parent;
498 | Item = item;
499 | }
500 |
501 | public override string ToString()
502 | {
503 | return Item.ToString();
504 | }
505 | }
506 | }
507 |
--------------------------------------------------------------------------------
/DarkSouls3.TextViewer/TextViewer.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Duncan Ogilvie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dark Souls 3 Text Viewer
2 |
3 | [](https://ci.appveyor.com/project/mrexodia/darksouls3-textviewer)
4 |
5 | This tool helps you view all in-game text of [Dark Souls 3](https://www.darksouls3.com).
6 |
7 | **Disclaimer**: The contents of the `ds3.json` file are derived from the Dark Souls 3 game files owned by [From Software](http://www.fromsoftware.jp). They are extracted for research purposes and there will be no commercial usage.
8 |
9 | 
10 |
11 | ## Download
12 |
13 | You can find a snapshot of the latest commit [here](https://ci.appveyor.com/project/mrexodia/darksouls3-textviewer/build/artifacts). Signed, more stable versions can be found [here](https://github.com/mrexodia/DarkSouls3.TextViewer/releases)
14 |
15 | ## Filters
16 |
17 | You can use filters to find relevant information. Text is compared case-insensitive and you can combine multiple filters with operators & (AND) | (OR) ~ (NOT).
18 |
19 | - Identifiers can be found with '{id}'
20 | - DLC version can be found with 'dlcN'
21 | - Item type can be found with '{type}'
22 |
23 | Operators are evaluated in the following order:
24 |
25 | 1. Parentheses
26 | 2. NOT
27 | 3. AND
28 | 4. OR
29 |
30 | ```
31 | a|(b&c|~d) = a|((b&c)|(~d))
32 | ```
33 |
34 | ### Examples
35 |
36 | - Filter: `aldrich|deep`
37 | - Effect: Everything containing 'aldrich' or 'deep'
38 |
39 |
40 | - Filter: `god&swamp`
41 | - Effect: Everything containing 'god' and 'swamp'
42 |
43 |
44 | - Filter: `aldrich&deep|children`
45 | - Effect: With braces: aldrich&(deep|children)
46 |
47 |
48 | - Filter: `{1200}`
49 | - Effect: Matches text with ID 1200
50 |
51 |
52 | - Filter: `magic&~{Magic}`
53 | - Effect: All non-{Magic} items containing 'magic'
--------------------------------------------------------------------------------
/blacklist_engUS.txt:
--------------------------------------------------------------------------------
1 | after
2 | again
3 | against
4 | all
5 | along
6 | also
7 | and
8 | any
9 | are
10 | became
11 | become
12 | been
13 | boost
14 | boosts
15 | but
16 | can
17 | day
18 | def
19 | did
20 | else
21 | enter
22 | even
23 | ever
24 | few
25 | for
26 | from
27 | great
28 | had
29 | has
30 | have
31 | her
32 | hers
33 | him
34 | his
35 | increases
36 | instantly
37 | into
38 | its
39 | know
40 | known
41 | led
42 | like
43 | made
44 | many
45 | more
46 | most
47 | much
48 | not
49 | now
50 | once
51 | one
52 | only
53 | other
54 | out
55 | over
56 | remain
57 | remains
58 | said
59 | say
60 | see
61 | she
62 | since
63 | skill
64 | still
65 | tell
66 | tells
67 | than
68 | that
69 | the
70 | their
71 | them
72 | then
73 | there
74 | these
75 | they
76 | this
77 | those
78 | though
79 | thus
80 | too
81 | took
82 | until
83 | upon
84 | use
85 | used
86 | very
87 | was
88 | were
89 | what
90 | when
91 | where
92 | which
93 | while
94 | who
95 | whom
96 | will
97 | with
98 | wore
99 | would
100 | yet
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # How to extract the required files from the game?
2 |
3 | 1. Get [BinderTool](https://github.com/Atvaark/BinderTool) and put it in your `PATH` environment variable.
4 | 2. `BinderTool.exe Data1.bdt data`.
5 | 3. Copy the folders from `data\msg` in a separate folder.
6 | 4. Run `extractbnd.bat` from that folder.
7 | 5. Run `extractfmg.bat` from that folder.
8 | 6. Run `deletefmg.bat` from that folder.
9 | 7. Run `DarkSouls3.Preprocessor` to properly extract the textual data to JSON.
--------------------------------------------------------------------------------
/docs/deletefmg.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd INTERROOT_win64
3 | for /R %%i in (*.fmg) do del "%%i"
--------------------------------------------------------------------------------
/docs/extractbnd.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | for /r %%i in (*.msgbnd) do BinderTool.exe "%%i" .
--------------------------------------------------------------------------------
/docs/extractfmg.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd INTERROOT_win64
3 | for /R %%i in (*.fmg) do BinderTool.exe "%%i"
--------------------------------------------------------------------------------
/release.bat:
--------------------------------------------------------------------------------
1 | rmdir /S /Q release
2 | mkdir release
3 | copy DarkSouls3.TextViewer\bin\Release\DarkSouls3.TextViewer.exe release\
4 | copy DarkSouls3.TextViewer\bin\Release\DarkSouls3.Structures.dll release\
5 | copy ds3.json release\
--------------------------------------------------------------------------------