2
3
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-15 10:54:18 +00:00

Compare commits

...

118 Commits

Author SHA1 Message Date
4b0ab75a79 Merge branch 'ticket/49' 2022-11-12 10:30:24 -07:00
dcb0309a08 closes #49 2022-11-12 10:29:57 -07:00
7dde0855dc Merge branch 'ticket/48' 2022-11-12 10:13:57 -07:00
44c9b0694d Merge branch 'ticket/47' 2022-11-12 10:13:53 -07:00
dedf04ac43 Merge branch 'ticket/45' 2022-11-12 10:13:50 -07:00
eeb458817f Merge branch 'ticket/44' 2022-11-12 10:13:43 -07:00
68c7187155 closes #48 2022-11-12 10:13:17 -07:00
6fa695a2c3 closes #47 2022-11-12 10:12:53 -07:00
2a3c1b32ef closes #45 2022-11-12 10:11:59 -07:00
d3cbaa94ef closes #44 2022-11-12 10:11:24 -07:00
e7758ccc10 Merge branch 'ticket/49' 2022-10-23 10:46:15 -06:00
07b92234ad Fix bug for python SDL variable-length arrays 2022-10-03 21:48:57 -05:00
7dfa2ba56a Merge branch 'master' into working 2022-07-19 08:55:00 -06:00
1a091b7019 Merge branch 'ticket/48' 2022-06-05 15:14:09 -06:00
104a5ef4ee Merge branch 'ticket/47' 2022-06-05 15:13:55 -06:00
19cfaaaea9 Merge branch 'ticket/45' 2022-06-05 15:13:41 -06:00
dafd190083 Merge branch 'ticket/44' 2022-06-05 15:13:26 -06:00
fdee5a921b Merge branch 'ticket/47' of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata into ticket/47 2022-05-30 14:23:43 -07:00
b322ee094c Fix compile error 2022-05-30 14:23:20 -07:00
54c768d966 PR from Huru to prevent dynamics from moving during age initilization 2022-05-30 14:22:12 -07:00
82159bcb4a Merge branch 'ticket/47' of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata into ticket/47 2022-05-30 14:04:22 -07:00
b81eb21145 Fix compile error
Author: Adam Johnson <AdamJohnso@gmail.com>
2022-05-30 14:03:33 -07:00
e7b4f5c6ba Fix compile error
(cherry picked from commit 202e846a56)
2022-05-11 15:20:16 -06:00
202e846a56 Fix compile error 2022-05-11 14:16:44 -07:00
deb4858f3e Add subtitle and loc key message flags
(cherry picked from commit 126e7a76dd)
2022-05-11 13:58:51 -06:00
bff879abfd PR from Huru to prevent dynamics from moving during age initilization 2022-05-11 13:58:51 -06:00
fededb574b Change to prevent crashing when fCurStage is null 2022-05-11 13:58:51 -06:00
126e7a76dd Add subtitle and loc key message flags 2022-05-10 20:07:41 -05:00
26807a8d87 Merge branch 'ticket/47' 2022-05-05 09:45:42 -06:00
f54f14328e PR from Huru to prevent dynamics from moving during age initilization 2022-05-04 20:16:58 -07:00
311671e7a2 Merge branch 'ticket/46'
closes #46
2022-04-29 14:55:59 -06:00
8aaa98b8b7 Change to prevent crashing when fCurStage is null 2022-04-29 07:46:54 -07:00
3489e04463 Fix crash from plMouseDevice::HideCursor if it is called before cursor is created 2022-04-06 19:46:00 -05:00
33bbc490be Minor code quality correction 2022-04-06 19:32:30 -05:00
fd0c2a205e Fix nondeterministic conflicting page processing on startup 2022-04-06 19:18:05 -05:00
b2521e0777 Merge branch 'ticket/42'
closes #42
2022-03-23 09:22:29 -06:00
1f7de46bc2 Expand thread memory allocations for stack and heap to 1.25MB 2022-03-22 13:53:50 -06:00
f9d629cfc5 Expand thread memory allocations for stack and heap to 1.25MB 2022-03-22 13:52:03 -06:00
b16de9d86f Merge branch 'master' into working 2022-03-19 21:41:37 -06:00
aba5e2562c Merge branch 'ticket/38'
closes #38
2022-03-19 21:39:41 -06:00
bff8203fbe Merge branch 'ticket/38' of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata into ticket/38 2022-03-19 22:15:28 -05:00
23ded3210f By popular demand, enable subtitles by default 2022-03-19 22:15:14 -05:00
bbeb25d29a Merge branch 'master' into working 2022-03-12 09:16:15 -07:00
9f9d510958 Merge branch 'ticket/38'
closes #38
2022-03-12 09:15:42 -07:00
f0d2bd3eaa Don't feed remaining subtitles when audio skips to past the end of last subtitle
(cherry picked from commit 40bcaba9d8)
2022-03-11 10:05:46 -07:00
41627d1c7c Merge branch 'master' into working 2022-03-11 10:03:31 -07:00
ea4bb43623 Merge branch 'ticket/38' of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata into ticket/38 2022-03-11 10:59:08 -06:00
40bcaba9d8 Don't feed remaining subtitles when audio skips to past the end of last subtitle 2022-03-11 10:55:44 -06:00
e93db035ba Revert "Fixes bug where avatar run-lock state can get confused after alt-tabbing"
This reverts commit 69dac251b6.
2022-03-09 09:44:05 -07:00
94fab5996f Merge branch 'ticket/41'
closes #41
2022-03-09 09:42:23 -07:00
da7d2d0e5c Merge branch 'ticket/40'
closes #40
2022-03-09 09:41:57 -07:00
2e8dc81bf3 Merge branch 'ticket/38'
closes #38
2022-03-09 09:41:29 -07:00
c0e83259f3 Don't display previous subtitles all at once when subtitles are enabled mid-audio play
(cherry picked from commit 40f200e066)
2022-03-06 10:17:51 -07:00
838e3e51ad Merge branch 'ticket/38' of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata into ticket/38 2022-03-06 09:10:38 -06:00
40f200e066 Don't display previous subtitles all at once when subtitles are enabled mid-audio play 2022-03-06 09:04:27 -06:00
6e4996e1be Ensure pyGUIControlListBox::GetElementW can't attempt to return a null pointer as a std::wstring
(cherry picked from commit 2f1bb87056)
2022-03-05 12:42:42 -07:00
2f1bb87056 Ensure pyGUIControlListBox::GetElementW can't attempt to return a null pointer as a std::wstring 2022-03-05 13:34:52 -06:00
df848b48c4 Prevent deferred link race conditions
(cherry picked from commit e512dd0c68)
2022-03-04 13:16:31 -07:00
75c570877a Merge branch 'master' into working 2022-03-04 13:16:11 -07:00
e512dd0c68 Prevent deferred link race conditions 2022-03-03 23:26:08 -06:00
4c76549fb3 Merge branch 'ticket/33'
closes #33
2022-03-01 14:42:05 -07:00
1a930cb47f Merge branch 'ticket/38'
closes #38
2022-03-01 11:02:25 -07:00
b9af23e458 Merge branch 'ticket/37'
closes #37
2022-03-01 11:02:04 -07:00
9e2e2d02e1 Merge branch 'ticket/36'
closes #36
2022-03-01 11:01:42 -07:00
7a73c2d8e3 Merge branch 'ticket/34'
closes #34
2022-03-01 11:01:03 -07:00
933cbe2fe7 Merge branch 'ticket/32'
closes #32
2022-03-01 11:00:22 -07:00
fe88f2e8a2 Merge branch 'ticket/31'
closes #31
2022-03-01 10:59:54 -07:00
9e308cbebe Fix another log string formatting issue found by Adam. 2022-02-26 20:22:41 -06:00
126d7511e0 Fix parentheses mistake for retrieving streaming audio timings and apply code fix suggestions from Adam 2022-02-26 19:16:00 -06:00
64323c6073 Apply code suggestions from rarified 2022-02-26 11:57:56 -06:00
3b17e20fb9 Revert "Initial port of Mystler's code"
This reverts commit b0511ea068.
2022-02-25 15:28:04 -07:00
8a2534dff6 Simplify SRT file path construction with suggestion from Hoikas 2022-02-25 14:34:30 -06:00
25ea208084 Revert "Add read and write file functions for clothing"
This reverts commit afed53f920.
2022-02-25 13:07:17 -07:00
a392a37fcd Revert "Change to ReadFromFile command per rarified"
This reverts commit f90ab01d44.
2022-02-25 13:07:15 -07:00
7c64654e1f Revert "More odds and ends from Mystler's PRs"
This reverts commit a82188cbf4.
2022-02-25 13:07:10 -07:00
9a1b37e7f6 Turn std::strings into char* before doing PyObject_CallMethod with them 2022-02-25 12:14:44 -06:00
1012251d9a Add missing message dispatch registration 2022-02-25 01:07:40 -06:00
1d65c78097 Fix bad include, missing static declaration, SRT path directory, and formatting 2022-02-25 01:06:29 -06:00
c50bb08e8d Fix usage and overflow bug causing plWin32StreamingSound::GetActualTimeSec() to return absurd values. Needed fix for subtitle timings. 2022-02-23 21:46:02 -06:00
229883654e Initial pass at getting subtitle support in. Doesn't compile for unknown reasons 2022-02-23 21:35:03 -06:00
a82188cbf4 More odds and ends from Mystler's PRs
(cherry picked from commit eb40f86349)
2022-02-20 11:08:49 -07:00
f90ab01d44 Change to ReadFromFile command per rarified
(cherry picked from commit 9e83bf7c8d)
2022-02-20 11:08:26 -07:00
afed53f920 Add read and write file functions for clothing
(cherry picked from commit 4f13d37905)
2022-02-20 11:08:26 -07:00
b0511ea068 Initial port of Mystler's code
Add coding from Mystler's original commits

(cherry picked from commit 6b3b966f81)
2022-02-20 11:08:24 -07:00
dfc89b363c Don't update to visible arrow when cursor should be hidden
(cherry picked from commit 51b6b4750b)
2022-02-20 10:02:49 -07:00
9ab07771df Fixes bug where avatar run-lock state can get confused after alt-tabbing
(cherry picked from commit 69dac251b6)
2022-02-20 10:02:44 -07:00
51b6b4750b Don't update to visible arrow when cursor should be hidden 2022-02-18 20:19:15 -06:00
69dac251b6 Fixes bug where avatar run-lock state can get confused after alt-tabbing 2022-02-18 18:11:37 -06:00
fd260827aa Fix error due to no Empty()
(cherry picked from commit e81af06584)
2022-01-24 20:56:41 -07:00
e81af06584 Fix error due to no Empty() 2022-01-24 19:06:23 -08:00
da5ba1062b Files for Allowing disabling avatar panic links
(cherry picked from commit 5f3a8644a7)
2022-01-24 15:43:15 -07:00
5f3a8644a7 Files for Allowing disabling avatar panic links 2022-01-24 14:22:04 -08:00
8291326614 Ensure we don't try to get localized values for null objectnames
(cherry picked from commit b00c7729cc)
2022-01-24 14:59:45 -07:00
90e67f6206 Changes needed so climbing works correctly with wall
(cherry picked from commit 62089be53f)
2022-01-07 13:04:20 -07:00
a974c9f1b2 Update error messages for new variable 2022-01-07 13:03:44 -07:00
f05d71a214 Adds default clothing changes broadcast to other clients 2022-01-07 13:03:10 -07:00
a317ae4b08 Merge branch 'master' into working 2022-01-07 12:57:27 -07:00
62089be53f Changes needed so climbing works correctly with wall 2022-01-07 11:31:11 -08:00
391bbaa4e7 Update error messages for new variable 2021-12-15 09:23:54 -08:00
84eedce685 Merge branch 'ticket/32' 2021-12-13 21:37:56 -07:00
924152da98 oops kwlist was wrong 2021-12-13 20:35:17 -08:00
8a42f86dc2 Merge branch 'ticket/32' 2021-12-13 18:54:10 -07:00
587414dfa5 Adds default clothing changes broadcast to other clients 2021-12-13 16:25:15 -08:00
b00c7729cc Ensure we don't try to get localized values for null objectnames 2021-12-03 20:08:31 -06:00
916bf4f87f Graphics cleanup for old graphics card tunables.
c.f. H'uru commits:

>    commit e4e718e243
>    Author: Adam Johnson <AdamJohnso@gmail.com>
>    Date:   Fri Feb 1 17:19:50 2013 -0500
>
>        Bypass ATI Generic fudging with Radeon HD cards

>    commit bbae6a76d7
>    Author: Adam Johnson <AdamJohnso@gmail.com>
>    Date:   Sat Nov 30 20:02:08 2013 -0500
>
>        We don't support 3dfx cards...
>
>        Come on, man... They made some good cards, but they went out of business
>        in 1999! Ain't nobody got time fo' dat.

>    commit a30a326d17
>    Author: Adam Johnson <AdamJohnso@gmail.com>
>    Date:   Sat Nov 30 20:06:19 2013 -0500
>
>        We only support DirectX 9...
>
>        If you have less than 11MB VRAM or need to use the ref implementation,
>        then you are using a dinosaur and have no business even attempting to play
>        this game.

>    commit 544abef39e
>    Author: Adam Johnson <AdamJohnso@gmail.com>
>    Date:   Sat Nov 30 20:41:56 2013 -0500
>
>        Wow, those cards are old...
>
>        Remove detection for cards that are don't support at LEAST DirectX 8.
>        There's no way they would even be able to get past Direct3DCreate9, so we
>        shouldn't need to worry about them... I hope.

>    commit 9070d70e50
>    Author: Branan Purvine-Riley <branan@gmail.com>
>    Date:   Sat Jul 27 14:50:20 2013 -0700
>
>        Lots of cleanups to hsG3DeviceDelector

>    commit ac23835384
>    Author: Branan Purvine-Riley <branan@gmail.com>
>    Date:   Sat Jul 27 15:09:24 2013 -0700
>
>        Get rid of obsolete readers/writes for device info

>    commit fc67738ee8
>    Author: Branan Purvine-Riley <branan@gmail.com>
>    Date:   Sat Jul 27 15:50:10 2013 -0700
>
>        Remove some obviously obsolete caps

>    commit 60c544e1ff
>    Author: Adam Johnson <AdamJohnso@gmail.com>
>    Date:   Fri Nov 29 23:42:20 2013 -0500
>
>        Don't lazy-load D3D9.dll
>
>        We already link against it, so that's just a waste of time. Also, cleanup
>        some unneeded ddraw includes. Remember that in Direct3D9, all devices can
>        render in windowed mode.

(cherry picked from commit 95ab8161f0)
2021-11-17 09:46:09 -07:00
2160831221 Always decompress OGGs updated by plUruLauncher.
This prevents users from needing to manually delete files from their
streamingCache folder when an audio file is updated. Note that this will
not fix streamingCaches that are already in a borked state.

(cherry picked from commit fa41ec7f16)
2021-11-17 09:46:01 -07:00
e8e9cd29ee Fix #ifdef limiting Plasma App.SetLanguage command access in Internal client.
(cherry picked from commit 7be998219f)
2021-11-05 15:43:11 -06:00
c9fddca6d5 Fix garbled stack traces.
Newer versions of VS and Windows use ASLR for security purposes, meaning
that the module may be relocated from what is expected by the linker map
file. While we could kludge around that by disabling ASLR, it would be
better to just map the actual stack addresses to the expected addresses.
This also simplifies all of the weird segment math to simply use the
rvabase value in the map file.
2021-10-19 15:02:02 -06:00
3f8eaf6a9a Add console command App.Crash to debug garbled stack traces. 2021-10-19 15:02:02 -06:00
0ce35e84b2 Remove old SDK code from CWE source base. Now entirely in SDK submodule. 2021-10-19 15:01:40 -06:00
31156794ad Fix reference counting problem in pyVaultNode::AddNode().
This is fixed in H'uru via extensive use of RAII around vault nodes.
2021-10-17 16:30:07 -06:00
fc79b5f45a Fix vaultOperation Python object leak.
This fixes a leak of a Python bound method. Leaking this means that
PythonFileMods keys are still loaded when the client exits. These
methods are most commonly used by xSimpleImager.py, so the effect of the
leak can be observed by simply linking to Relto and quitting with a leak
detector active.
2021-10-17 16:30:07 -06:00
542711c7c0 Fix misplaced return value.
The "wait for server response" return value was short-circuiting the
"already done" value. The previous commit fixed always needing a new
instance, exposing this problem.
2021-10-17 16:28:51 -06:00
b9f8e3d1bd Review changes cf. Adam: change name of local vars to not start
with 'f' prefix (used for fields in objects).
Also removed trailing space from lines that irritate Git difference listings.
2021-10-16 15:19:45 -06:00
224ad908cc Fix incorrect string handling in pfJournalBook::IRenderPage()
Unify references to HTML string chunk as being accessed as wchar_t[]
strings rather than repeatedly calling std::wstring.c_str() on the
chunk, then using character positions obtained from those strings
to index directly into the std::wstring[] form from chunk->fText.
2021-10-16 15:19:45 -06:00
ed516b6508 Fix wild access to font structures when rendering non-ascii unicode characters. 2021-10-16 15:06:11 -06:00
4329212d98 Fix assertion with incorrect limit on age sequence prefix. 2021-10-16 15:06:02 -06:00
8ff71fb384 Correct calls to StrTo(Unicode|Ansi) to use the correct size. 2021-10-16 14:53:27 -06:00
50 changed files with 853 additions and 151 deletions

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug_Internal|Win32"> <ProjectConfiguration Include="Debug_Internal|Win32">
@ -121,6 +121,8 @@
<MapFileName>$(OutDir)$(TargetName).map</MapFileName> <MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<MapExports>true</MapExports> <MapExports>true</MapExports>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<HeapReserveSize>0x140000</HeapReserveSize>
<StackReserveSize>0x140000</StackReserveSize>
</Link> </Link>
<Midl> <Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -177,6 +179,8 @@
<MapFileName>$(OutDir)$(TargetName).map</MapFileName> <MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<MapExports>true</MapExports> <MapExports>true</MapExports>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<HeapReserveSize>0x140000</HeapReserveSize>
<StackReserveSize>0x140000</StackReserveSize>
</Link> </Link>
<Midl> <Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -237,6 +241,8 @@
<TargetMachine>MachineX86</TargetMachine> <TargetMachine>MachineX86</TargetMachine>
<MapExports>true</MapExports> <MapExports>true</MapExports>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<HeapReserveSize>0x140000</HeapReserveSize>
<StackReserveSize>0x140000</StackReserveSize>
</Link> </Link>
<Midl> <Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -298,6 +304,8 @@
<TargetMachine>MachineX86</TargetMachine> <TargetMachine>MachineX86</TargetMachine>
<MapExports>true</MapExports> <MapExports>true</MapExports>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<HeapReserveSize>0x140000</HeapReserveSize>
<StackReserveSize>0x140000</StackReserveSize>
</Link> </Link>
<Midl> <Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

View File

@ -244,6 +244,7 @@
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release_Internal|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release_Internal|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.cpp" />
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.cpp"> <ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug_Internal|Win32'">Disabled</Optimization> <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug_Internal|Win32'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization> <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
@ -315,6 +316,7 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioFileReader.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioFileReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plBufferedFileReader.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plBufferedFileReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plFastWavReader.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plFastWavReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plOGGCodec.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundBuffer.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundBuffer.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundDeswizzler.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSoundDeswizzler.h" />

View File

@ -32,6 +32,9 @@
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.cpp"> <ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioCore.h"> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plAudioCore.h">
@ -61,5 +64,8 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.h"> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudio\plWavFile.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plAudioCore\plSrtFileReader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -817,6 +817,7 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSimStateMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSimStateMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnModMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnModMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnRequestMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSpawnRequestMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSubtitleMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSwimMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSwimMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSynchEnableMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSynchEnableMsg.h" />
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plTimerCallbackMsg.h" /> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plTimerCallbackMsg.h" />

View File

@ -361,5 +361,8 @@
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plVaultNotifyMsg.h"> <ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plVaultNotifyMsg.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\..\Sources\Plasma\PubUtilLib\plMessage\plSubtitleMsg.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -2313,6 +2313,7 @@ void plClient::IDetectAudioVideoSettings()
WriteInt(stream, "Audio.SetChannelVolume Ambience", 1); WriteInt(stream, "Audio.SetChannelVolume Ambience", 1);
WriteInt(stream, "Audio.SetChannelVolume NPCVoice", 1); WriteInt(stream, "Audio.SetChannelVolume NPCVoice", 1);
WriteInt(stream, "Audio.EnableVoiceRecording", 1); WriteInt(stream, "Audio.EnableVoiceRecording", 1);
WriteInt(stream, "Audio.EnableSubtitles", true);
WriteString(stream, "Audio.SetDeviceName", deviceName ); WriteString(stream, "Audio.SetDeviceName", deviceName );
stream->Close(); stream->Close();
delete stream; delete stream;

View File

@ -499,6 +499,22 @@ void plVirtualCam1::SetCutNextTrans()
#endif #endif
} }
void plVirtualCam1::SetCutNext()
{
plCameraModifier1* cam = GetCurrentCamera();
if (cam && cam->GetBrain()) {
cam->GetBrain()->SetFlags(plCameraBrain1::kCutPosOnce);
cam->GetBrain()->SetFlags(plCameraBrain1::kCutPOAOnce);
}
SetFlags(kCutNextTrans);
SetRender(true);
#ifdef STATUS_LOG
camLog->AddLineF("Set Camera to cut on next frame");
#endif
}
void plVirtualCam1::SetRender(hsBool render) void plVirtualCam1::SetRender(hsBool render)
{ {
fFlags.SetBit(kRender,render); fFlags.SetBit(kRender,render);

View File

@ -85,6 +85,7 @@ public:
enum flags enum flags
{ {
kSetFOV, kSetFOV,
/** Forces the next camera transition to be cut. */
kCutNextTrans, kCutNextTrans,
kRender, kRender,
kRegionIgnore, kRegionIgnore,
@ -145,6 +146,7 @@ public:
hsPoint3 GetCameraPOA() { return fOutputPOA; } hsPoint3 GetCameraPOA() { return fOutputPOA; }
hsVector3 GetCameraUp() { return fOutputUp; } hsVector3 GetCameraUp() { return fOutputUp; }
void SetCutNextTrans(); // used when player warps into a new camera region void SetCutNextTrans(); // used when player warps into a new camera region
void SetCutNext();
const hsMatrix44 GetCurrentMatrix() { return fMatrix; } const hsMatrix44 GetCurrentMatrix() { return fMatrix; }
static plVirtualCam1* Instance() { return fInstance; } static plVirtualCam1* Instance() { return fInstance; }

View File

@ -3391,6 +3391,11 @@ PF_CONSOLE_CMD( Audio, MuteAll, "bool on", "Mute or unmute all sounds")
plgAudioSys::SetMuted( (bool)params[ 0 ] ); plgAudioSys::SetMuted( (bool)params[ 0 ] );
} }
PF_CONSOLE_CMD(Audio, EnableSubtitles, "bool on", "Enable or disable displaying subtitles for audio files containing speech")
{
plgAudioSys::SetEnableSubtitles((bool)params[0]);
}
PF_CONSOLE_CMD( Audio, SetDistanceModel, "int type", "Sets the distance model for all 3d sounds") PF_CONSOLE_CMD( Audio, SetDistanceModel, "int type", "Sets the distance model for all 3d sounds")
{ {
if(plgAudioSys::Sys()) if(plgAudioSys::Sys())

View File

@ -165,6 +165,8 @@ class pfKIMsg : public plMessage
kUNUSED1 = 0x00000008, kUNUSED1 = 0x00000008,
kStatusMsg = 0x00000010, kStatusMsg = 0x00000010,
kNeighborMsg = 0x00000020, // sending to all the neighbors kNeighborMsg = 0x00000020, // sending to all the neighbors
kSubtitleMsg = 0x00000040,
kLocKeyMsg = 0x00000080,
kChannelMask = 0x0000ff00 kChannelMask = 0x0000ff00
}; };

View File

@ -1978,3 +1978,12 @@ hsBool cyAvatar::IsCurrentBrainHuman()
} }
return false; return false;
} }
void cyAvatar::SetDontPanicLink(bool value)
{
if ( fRecvr.Count() > 0 ) {
plArmatureMod* mod = plAvatarMgr::FindAvatar(fRecvr[0]);
if (mod)
mod->SetDontPanicLinkFlag(value);
}
}

View File

@ -566,6 +566,14 @@ public:
static hsBool IsCurrentBrainHuman(); static hsBool IsCurrentBrainHuman();
/////////////////////////////////////////////////////////////////////////////
//
// Function : SetDontPanicLink
// PARAMETERS : value
//
// PURPOSE : Disables panic linking to Personal Age (warps the avatar back to the start instead)
//
void SetDontPanicLink(bool value);
}; };
#endif // cyAvatar_h #endif // cyAvatar_h

View File

@ -597,6 +597,18 @@ PYTHON_METHOD_DEFINITION(ptAvatar, playSimpleAnimation, args)
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }
PYTHON_METHOD_DEFINITION(ptAvatar, setDontPanicLink, args)
{
bool value;
if (!PyArg_ParseTuple(args, "b", &value)) {
PyErr_SetString(PyExc_TypeError, "setDontPanicLink expects a boolean");
PYTHON_RETURN_ERROR;
}
self->fThis->SetDontPanicLink(value);
PYTHON_RETURN_NONE;
}
PYTHON_START_METHODS_TABLE(ptAvatar) PYTHON_START_METHODS_TABLE(ptAvatar)
PYTHON_METHOD(ptAvatar, netForce, "Params: forceFlag\nSpecify whether this object needs to use messages that are forced to the network\n" PYTHON_METHOD(ptAvatar, netForce, "Params: forceFlag\nSpecify whether this object needs to use messages that are forced to the network\n"
"- This is to be used if your Python program is running on only one client\n" "- This is to be used if your Python program is running on only one client\n"
@ -651,6 +663,8 @@ PYTHON_START_METHODS_TABLE(ptAvatar)
PYTHON_METHOD(ptAvatar, unRegisterForBehaviorNotify, "Params: selfKey\nThis will unregister behavior notifications"), PYTHON_METHOD(ptAvatar, unRegisterForBehaviorNotify, "Params: selfKey\nThis will unregister behavior notifications"),
PYTHON_METHOD(ptAvatar, playSimpleAnimation, "Params: animName\nPlay simple animation on avatar"), PYTHON_METHOD(ptAvatar, playSimpleAnimation, "Params: animName\nPlay simple animation on avatar"),
PYTHON_METHOD(ptAvatar, setDontPanicLink, "Params: value\nDisables panic linking to Personal Age (warps the avatar back to the start instead)"),
PYTHON_END_METHODS_TABLE; PYTHON_END_METHODS_TABLE;
PYTHON_GLOBAL_METHOD_DEFINITION(PtSetBehaviorLoopCount, args, "Params: behaviorKey,stage,loopCount,netForce\nThis will set the loop count for a particular stage in a multistage behavior") PYTHON_GLOBAL_METHOD_DEFINITION(PtSetBehaviorLoopCount, args, "Params: behaviorKey,stage,loopCount,netForce\nThis will set the loop count for a particular stage in a multistage behavior")

View File

@ -2602,7 +2602,7 @@ void cyMisc::WearMaintainerSuit(pyKey& key, hsBool wear)
} }
void cyMisc::WearDefaultClothing(pyKey& key) void cyMisc::WearDefaultClothing(pyKey& key, hsBool broadcast)
{ {
if (key.getKey() != plNetClientMgr::GetInstance()->GetLocalPlayerKey()) if (key.getKey() != plNetClientMgr::GetInstance()->GetLocalPlayerKey())
return; return;
@ -2611,11 +2611,11 @@ void cyMisc::WearDefaultClothing(pyKey& key)
if (avMod) if (avMod)
{ {
avMod->GetClothingOutfit()->WearDefaultClothing(); avMod->GetClothingOutfit()->WearDefaultClothing(broadcast);
} }
} }
void cyMisc::WearDefaultClothingType(pyKey& key, UInt32 type) void cyMisc::WearDefaultClothingType(pyKey& key, UInt32 type, hsBool broadcast)
{ {
if (key.getKey() != plNetClientMgr::GetInstance()->GetLocalPlayerKey()) if (key.getKey() != plNetClientMgr::GetInstance()->GetLocalPlayerKey())
return; return;
@ -2624,7 +2624,7 @@ void cyMisc::WearDefaultClothingType(pyKey& key, UInt32 type)
if (avMod) if (avMod)
{ {
avMod->GetClothingOutfit()->WearDefaultClothingType(type); avMod->GetClothingOutfit()->WearDefaultClothingType(type, broadcast);
} }
} }

View File

@ -875,8 +875,8 @@ public:
// //
static void WearMaintainerSuit(pyKey& key, hsBool wear); static void WearMaintainerSuit(pyKey& key, hsBool wear);
static void WearDefaultClothing(pyKey& key); static void WearDefaultClothing(pyKey& key, hsBool broadcast = false);
static void WearDefaultClothingType(pyKey& key, UInt32 type); static void WearDefaultClothingType(pyKey& key, UInt32 type, hsBool broadcast = false);
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //

View File

@ -598,22 +598,24 @@ PYTHON_GLOBAL_METHOD_DEFINITION(PtFakeLinkAvatarToObject, args, "Params: avatar,
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }
PYTHON_GLOBAL_METHOD_DEFINITION(PtWearDefaultClothingType, args, "Params: key,type\nForces the avatar to wear the default clothing of the specified type") PYTHON_GLOBAL_METHOD_DEFINITION_WKEY(PtWearDefaultClothingType, args, kw, "Params: key,type,broadcast=false\nForces the avatar to wear the default clothing of the specified type")
{ {
char* kwlist[] = { "key", "type", "broadcast", NULL };
PyObject* keyObj = NULL; PyObject* keyObj = NULL;
unsigned long type; unsigned long type;
if (!PyArg_ParseTuple(args, "Ol", &keyObj, &type)) bool broadcast = false;
if (!PyArg_ParseTupleAndKeywords(args, kw, "Ol|b", kwlist, &keyObj, &type, &broadcast))
{ {
PyErr_SetString(PyExc_TypeError, "PtWearDefaultClothingType expects a ptKey and an unsigned long"); PyErr_SetString(PyExc_TypeError, "PtWearDefaultClothingType expects a ptKey, an unsigned long, and an optional bool");
PYTHON_RETURN_ERROR; PYTHON_RETURN_ERROR;
} }
if (!pyKey::Check(keyObj)) if (!pyKey::Check(keyObj))
{ {
PyErr_SetString(PyExc_TypeError, "PtWearDefaultClothingType expects a ptKey and an unsigned long"); PyErr_SetString(PyExc_TypeError, "PtWearDefaultClothingType expects a ptKey, an unsigned long, and an optional bool");
PYTHON_RETURN_ERROR; PYTHON_RETURN_ERROR;
} }
pyKey* key = pyKey::ConvertFrom(keyObj); pyKey* key = pyKey::ConvertFrom(keyObj);
cyMisc::WearDefaultClothingType(*key, type); cyMisc::WearDefaultClothingType(*key, type, broadcast);
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }

View File

@ -529,21 +529,23 @@ PYTHON_GLOBAL_METHOD_DEFINITION(PtWearMaintainerSuit, args, "Params: key,wearOrN
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }
PYTHON_GLOBAL_METHOD_DEFINITION(PtWearDefaultClothing, args, "Params: key\nForces the avatar to wear the default clothing set") PYTHON_GLOBAL_METHOD_DEFINITION_WKEY(PtWearDefaultClothing, args, kw, "Params: key, broadcast=false\nForces the avatar to wear the default clothing set")
{ {
char* kwlist[] = { "key", "broadcast", NULL };
PyObject* keyObj = NULL; PyObject* keyObj = NULL;
if (!PyArg_ParseTuple(args, "O", &keyObj)) bool broadcast = false;
if (!PyArg_ParseTupleAndKeywords(args, kw, "O|b", kwlist, &keyObj, &broadcast))
{ {
PyErr_SetString(PyExc_TypeError, "PtWearDefaultClothing expects a ptKey"); PyErr_SetString(PyExc_TypeError, "PtWearDefaultClothing expects a ptKey and an optional bool");
PYTHON_RETURN_ERROR; PYTHON_RETURN_ERROR;
} }
if (!pyKey::Check(keyObj)) if (!pyKey::Check(keyObj))
{ {
PyErr_SetString(PyExc_TypeError, "PtWearDefaultClothing expects a ptKey"); PyErr_SetString(PyExc_TypeError, "PtWearDefaultClothing expects a ptKey and an optional bool");
PYTHON_RETURN_ERROR; PYTHON_RETURN_ERROR;
} }
pyKey* key = pyKey::ConvertFrom(keyObj); pyKey* key = pyKey::ConvertFrom(keyObj);
cyMisc::WearDefaultClothing(*key); cyMisc::WearDefaultClothing(*key, broadcast);
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }

View File

@ -94,6 +94,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "../pfGameMgr/pfGameMgr.h" #include "../pfGameMgr/pfGameMgr.h"
#include "../plMessage/plAIMsg.h" #include "../plMessage/plAIMsg.h"
#include "../plAvatar/plAvBrainCritter.h" #include "../plAvatar/plAvBrainCritter.h"
#include "../plMessage/plSubtitleMsg.h"
#include "plProfile.h" #include "plProfile.h"
@ -189,6 +190,7 @@ char* plPythonFileMod::fFunctionNames[] =
{ "OnGameMgrMsg" }, // kfunc_OnGameMgrMsg { "OnGameMgrMsg" }, // kfunc_OnGameMgrMsg
{ "OnGameCliMsg" }, // kfunc_OnGameCliMsg { "OnGameCliMsg" }, // kfunc_OnGameCliMsg
{ "OnAIMsg" }, // kfunc_OnAIMsg { "OnAIMsg" }, // kfunc_OnAIMsg
{ "OnSubtitleMsg" }, // kfunc_OnSubtitleMsg
{ nil } { nil }
}; };
@ -828,6 +830,8 @@ void plPythonFileMod::AddTarget(plSceneObject* sobj)
// the message that is spammed to anyone who will listen // the message that is spammed to anyone who will listen
plgDispatch::Dispatch()->RegisterForExactType(plAIBrainCreatedMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plAIBrainCreatedMsg::Index(), GetKey());
} }
if (fPyFunctionInstances[kfunc_OnSubtitleMsg])
plgDispatch::Dispatch()->RegisterForExactType(plSubtitleMsg::Index(), GetKey());
// As the last thing... call the OnInit function if they have one // As the last thing... call the OnInit function if they have one
if ( fPyFunctionInstances[kfunc_Init] != nil ) if ( fPyFunctionInstances[kfunc_Init] != nil )
@ -2780,6 +2784,36 @@ hsBool plPythonFileMod::MsgReceive(plMessage* msg)
} }
} }
if (fPyFunctionInstances[kfunc_OnSubtitleMsg])
{
plSubtitleMsg* pSubMsg = plSubtitleMsg::ConvertNoRef(msg);
if (pSubMsg)
{
plProfile_BeginTiming(PythonUpdate);
PyObject* retVal = PyObject_CallMethod(
fPyFunctionInstances[kfunc_OnSubtitleMsg], fFunctionNames[kfunc_OnSubtitleMsg],
"ss", pSubMsg->GetText().c_str(), pSubMsg->GetSpeaker().c_str());
if (retVal == nil)
{
#ifndef PLASMA_EXTERNAL_RELEASE
// for some reason this function didn't, remember that and not call it again
fPyFunctionInstances[kfunc_OnSubtitleMsg] = nil;
#endif //PLASMA_EXTERNAL_RELEASE
// if there was an error make sure that the stderr gets flushed so it can be seen
ReportError();
}
Py_XDECREF(retVal);
plProfile_EndTiming(PythonUpdate);
// display any output (NOTE: this would be disabled in production)
DisplayPythonOutput();
// we handled this message (I think)
return true;
}
}
return plModifier::MsgReceive(msg); return plModifier::MsgReceive(msg);
} }

View File

@ -202,6 +202,7 @@ public:
kfunc_OnGameMgrMsg, kfunc_OnGameMgrMsg,
kfunc_OnGameCliMsg, kfunc_OnGameCliMsg,
kfunc_OnAIMsg, kfunc_OnAIMsg,
kfunc_OnSubtitleMsg,
kfunc_lastone kfunc_lastone
}; };
// array of matching Python instance where the functions are, if defined // array of matching Python instance where the functions are, if defined

View File

@ -474,6 +474,12 @@ void plPythonSDLModifier::IPythonVarToSDL(plStateDataRecord* state, const char*
int count = PyTuple_Size(pyVar); int count = PyTuple_Size(pyVar);
plSimpleVarDescriptor::Type type = var->GetSimpleVarDescriptor()->GetType(); plSimpleVarDescriptor::Type type = var->GetSimpleVarDescriptor()->GetType();
// Ensure that variable length arrays match.
if (var->GetSimpleVarDescriptor()->IsVariableLength()) {
if (var->GetCount() != count)
var->Alloc(count);
}
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
PyObject* pyVarItem = PyTuple_GetItem(pyVar, i); PyObject* pyVarItem = PyTuple_GetItem(pyVar, i);

View File

@ -256,6 +256,22 @@ hsBool pyAudioControl::IsMuted()
return plgAudioSys::IsMuted(); return plgAudioSys::IsMuted();
} }
// Enable or disable displaying speech subtitles
void pyAudioControl::EnableSubtitles()
{
plgAudioSys::SetEnableSubtitles(true);
}
void pyAudioControl::DisableSubtitles()
{
plgAudioSys::SetEnableSubtitles(false);
}
bool pyAudioControl::AreSubtitlesEnabled() const
{
return plgAudioSys::AreSubtitlesEnabled();
}
hsBool pyAudioControl::SupportEAX(const char *deviceName) hsBool pyAudioControl::SupportEAX(const char *deviceName)
{ {
return plgAudioSys::SupportsEAX(deviceName); return plgAudioSys::SupportsEAX(deviceName);

View File

@ -109,6 +109,11 @@ public:
virtual void UnmuteAll(); virtual void UnmuteAll();
virtual hsBool IsMuted(); virtual hsBool IsMuted();
// Enable or disable displaying speech subtitles
void EnableSubtitles();
void DisableSubtitles();
bool AreSubtitlesEnabled() const;
virtual void SetAudioSystemMode(int mode); // sets the current mode virtual void SetAudioSystemMode(int mode); // sets the current mode
virtual int GetAudioSystemMode(); // returns the current mode virtual int GetAudioSystemMode(); // returns the current mode
virtual int GetHighestAudioMode(); // returns the highest mode the card is capable of handling virtual int GetHighestAudioMode(); // returns the highest mode the card is capable of handling

View File

@ -242,6 +242,14 @@ PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, isMuted)
PYTHON_RETURN_BOOL(self->fThis->IsMuted()); PYTHON_RETURN_BOOL(self->fThis->IsMuted());
} }
PYTHON_BASIC_METHOD_DEFINITION(ptAudioControl, enableSubtitles, EnableSubtitles)
PYTHON_BASIC_METHOD_DEFINITION(ptAudioControl, disableSubtitles, DisableSubtitles)
PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, areSubtitlesEnabled)
{
PYTHON_RETURN_BOOL(self->fThis->AreSubtitlesEnabled());
}
PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, canSetMicLevel) PYTHON_METHOD_DEFINITION_NOARGS(ptAudioControl, canSetMicLevel)
{ {
PYTHON_RETURN_BOOL(self->fThis->CanSetMicLevel()); PYTHON_RETURN_BOOL(self->fThis->CanSetMicLevel());
@ -484,6 +492,9 @@ PYTHON_START_METHODS_TABLE(ptAudioControl)
PYTHON_BASIC_METHOD(ptAudioControl, muteAll, "Mutes all sounds."), PYTHON_BASIC_METHOD(ptAudioControl, muteAll, "Mutes all sounds."),
PYTHON_BASIC_METHOD(ptAudioControl, unmuteAll, "Unmutes all sounds."), PYTHON_BASIC_METHOD(ptAudioControl, unmuteAll, "Unmutes all sounds."),
PYTHON_METHOD_NOARGS(ptAudioControl, isMuted, "Are all sounds muted? Returns 1 if true otherwise returns 0."), PYTHON_METHOD_NOARGS(ptAudioControl, isMuted, "Are all sounds muted? Returns 1 if true otherwise returns 0."),
PYTHON_BASIC_METHOD(ptAudioControl, enableSubtitles, "Enables audio subtitles."),
PYTHON_BASIC_METHOD(ptAudioControl, disableSubtitles, "Disables audio subtitles."),
PYTHON_METHOD_NOARGS(ptAudioControl, areSubtitlesEnabled, "Are audio subtitles enabled? Returns 1 if true otherwise returns 0."),
PYTHON_METHOD_NOARGS(ptAudioControl, canSetMicLevel, "Can the microphone level be set? Returns 1 if true otherwise returns 0."), PYTHON_METHOD_NOARGS(ptAudioControl, canSetMicLevel, "Can the microphone level be set? Returns 1 if true otherwise returns 0."),
PYTHON_METHOD(ptAudioControl, setMicLevel, "Params: level\nSets the microphone recording level (0.0 to 1.0)."), PYTHON_METHOD(ptAudioControl, setMicLevel, "Params: level\nSets the microphone recording level (0.0 to 1.0)."),
PYTHON_METHOD_NOARGS(ptAudioControl, getMicLevel, "Returns the microphone recording level (0.0 to 1.0)."), PYTHON_METHOD_NOARGS(ptAudioControl, getMicLevel, "Returns the microphone recording level (0.0 to 1.0)."),

View File

@ -587,16 +587,17 @@ std::wstring pyGUIControlListBox::GetElementW( UInt16 idx )
{ {
// if its a text element type then it should be safe to cast it to a pfGUIListText // if its a text element type then it should be safe to cast it to a pfGUIListText
pfGUIListText* letext = (pfGUIListText*)le; pfGUIListText* letext = (pfGUIListText*)le;
return letext->GetText(); return (letext->GetText() != nullptr) ? letext->GetText() : L"";
} }
else if ( le->GetType() == pfGUIListElement::kTreeRoot ) else if ( le->GetType() == pfGUIListElement::kTreeRoot )
{ {
pfGUIListTreeRoot* elroot = (pfGUIListTreeRoot*)le; pfGUIListTreeRoot* elroot = (pfGUIListTreeRoot*)le;
return elroot->GetTitle(); return (elroot->GetTitle() != nullptr) ? elroot->GetTitle() : L"";
} }
} }
} }
} }
return L""; return L"";
} }

View File

@ -34,9 +34,9 @@ work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at: or by snail mail at:
Cyan Worlds, Inc. Cyan Worlds, Inc.
14617 N Newport Hwy 14617 N Newport Hwy
Mead, WA 99021 Mead, WA 99021
*==LICENSE==*/ *==LICENSE==*/
@ -368,9 +368,10 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plRidingAnimatedPhysicalDetector), CLASS_INDEX(plRidingAnimatedPhysicalDetector),
CLASS_INDEX(plVolumeSensorConditionalObjectNoArbitration), CLASS_INDEX(plVolumeSensorConditionalObjectNoArbitration),
CLASS_INDEX(plPXSubWorld), CLASS_INDEX(plPXSubWorld),
//--------------------------------------------------------- CLASS_INDEX(pfConfirmationMgr),
// Keyed objects above this line, unkeyed (such as messages) below.. //---------------------------------------------------------
//--------------------------------------------------------- // Keyed objects above this line, unkeyed (such as messages) below..
//---------------------------------------------------------
CLASS_INDEX_NONKEYED_OBJ_START CLASS_INDEX_NONKEYED_OBJ_START
CLASS_INDEX(plObjRefMsg), CLASS_INDEX(plObjRefMsg),
@ -780,17 +781,17 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plShadowCastMsg), CLASS_INDEX(plShadowCastMsg),
CLASS_INDEX(plBoundsIsect), CLASS_INDEX(plBoundsIsect),
CLASS_INDEX(plResMgrHelperMsg), CLASS_INDEX(plResMgrHelperMsg),
CLASS_INDEX(plNetCommAuthMsg), CLASS_INDEX(plNetCommAuthMsg),
CLASS_INDEX(plNetCommFileListMsg), CLASS_INDEX(plNetCommFileListMsg),
CLASS_INDEX(plNetCommFileDownloadMsg), CLASS_INDEX(plNetCommFileDownloadMsg),
CLASS_INDEX(plNetCommLinkToAgeMsg), CLASS_INDEX(plNetCommLinkToAgeMsg),
CLASS_INDEX(plNetCommPlayerListMsg), CLASS_INDEX(plNetCommPlayerListMsg),
CLASS_INDEX(plNetCommActivePlayerMsg), CLASS_INDEX(plNetCommActivePlayerMsg),
CLASS_INDEX(plNetCommCreatePlayerMsg), CLASS_INDEX(plNetCommCreatePlayerMsg),
CLASS_INDEX(plNetCommDeletePlayerMsg), CLASS_INDEX(plNetCommDeletePlayerMsg),
CLASS_INDEX(plNetCommPublicAgeListMsg), CLASS_INDEX(plNetCommPublicAgeListMsg),
CLASS_INDEX(plNetCommPublicAgeMsg), CLASS_INDEX(plNetCommPublicAgeMsg),
CLASS_INDEX(plNetCommRegisterAgeMsg), CLASS_INDEX(plNetCommRegisterAgeMsg),
CLASS_INDEX(plVaultAdminInitializationTask), CLASS_INDEX(plVaultAdminInitializationTask),
CLASS_INDEX(plMultistageModMsg), CLASS_INDEX(plMultistageModMsg),
CLASS_INDEX(plSoundVolumeApplicator), CLASS_INDEX(plSoundVolumeApplicator),
@ -948,6 +949,17 @@ CLASS_INDEX_LIST_START
CLASS_INDEX(plAngularVelocityMsg), CLASS_INDEX(plAngularVelocityMsg),
CLASS_INDEX(plRideAnimatedPhysMsg), CLASS_INDEX(plRideAnimatedPhysMsg),
CLASS_INDEX(plAvBrainRideAnimatedPhysical), CLASS_INDEX(plAvBrainRideAnimatedPhysical),
CLASS_INDEX(pfGameScoreMsg), // This index and below are unused currently and placed for indexing plSubtitleMsg consistently with H'uru
CLASS_INDEX(pfGameScoreListMsg),
CLASS_INDEX(pfGameScoreTransferMsg),
CLASS_INDEX(pfGameScoreUpdateMsg),
CLASS_INDEX(plLoadClothingMsg),
CLASS_INDEX(plNullPipeline),
CLASS_INDEX(plGLPipeline),
CLASS_INDEX(plSDLModifierStateMsg),
CLASS_INDEX(plConfirmationMsg),
CLASS_INDEX(plLocalizedConfirmationMsg), // This index and above are unused currently and placed for indexing plSubtitleMsg consistently with H'uru
CLASS_INDEX(plSubtitleMsg),
CLASS_INDEX_LIST_END CLASS_INDEX_LIST_END
#endif // plCreatableIndex_inc #endif // plCreatableIndex_inc

View File

@ -43,7 +43,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#ifndef plLogicModBase_inc #ifndef plLogicModBase_inc
#define plLogicModBase_inc #define plLogicModBase_inc
#include <stdint.h> #include <cstdint>
#include "plSingleModifier.h" #include "plSingleModifier.h"
#include "../pnNetCommon/plSynchedValue.h" #include "../pnNetCommon/plSynchedValue.h"
#include "hsTemplates.h" #include "hsTemplates.h"

View File

@ -994,6 +994,7 @@ hsBool plgAudioSys::fInit = false;
hsBool plgAudioSys::fActive = false; hsBool plgAudioSys::fActive = false;
hsBool plgAudioSys::fUseHardware = false; hsBool plgAudioSys::fUseHardware = false;
hsBool plgAudioSys::fMuted = true; hsBool plgAudioSys::fMuted = true;
bool plgAudioSys::fEnableSubtitles = true;
hsBool plgAudioSys::fDelayedActivate = false; hsBool plgAudioSys::fDelayedActivate = false;
hsBool plgAudioSys::fEnableEAX = false; hsBool plgAudioSys::fEnableEAX = false;
hsWindowHndl plgAudioSys::fWnd = nil; hsWindowHndl plgAudioSys::fWnd = nil;
@ -1047,6 +1048,11 @@ void plgAudioSys::SetMuted( hsBool b )
SetGlobalFadeVolume(1.0); SetGlobalFadeVolume(1.0);
} }
void plgAudioSys::SetEnableSubtitles(bool b)
{
fEnableSubtitles = b;
}
void plgAudioSys::SetUseHardware(hsBool b) void plgAudioSys::SetUseHardware(hsBool b)
{ {
fUseHardware = b; fUseHardware = b;

View File

@ -193,11 +193,13 @@ public:
static void SetUseHardware(hsBool b); static void SetUseHardware(hsBool b);
static void SetActive(hsBool b); static void SetActive(hsBool b);
static void SetMuted( hsBool b ); static void SetMuted( hsBool b );
static void SetEnableSubtitles(bool b);
static void EnableEAX( hsBool b ); static void EnableEAX( hsBool b );
static hsBool Active() { return fInit; } static hsBool Active() { return fInit; }
static void Shutdown(); static void Shutdown();
static void Activate(hsBool b); static void Activate(hsBool b);
static hsBool IsMuted( void ) { return fMuted; } static hsBool IsMuted( void ) { return fMuted; }
static bool AreSubtitlesEnabled() { return fEnableSubtitles; }
static hsWindowHndl hWnd() { return fWnd; } static hsWindowHndl hWnd() { return fWnd; }
static plAudioSystem* Sys() { return fSys; } static plAudioSystem* Sys() { return fSys; }
static void Restart( void ); static void Restart( void );
@ -258,6 +260,7 @@ private:
static hsBool fInit; static hsBool fInit;
static hsBool fActive; static hsBool fActive;
static hsBool fMuted; static hsBool fMuted;
static bool fEnableSubtitles;
static hsWindowHndl fWnd; static hsWindowHndl fWnd;
static hsBool fUseHardware; static hsBool fUseHardware;
static hsBool fDelayedActivate; static hsBool fDelayedActivate;

View File

@ -710,9 +710,9 @@ hsBool plDSoundBuffer::IsEAXAccelerated( void ) const
//// BytePosToMSecs ////////////////////////////////////////////////////////// //// BytePosToMSecs //////////////////////////////////////////////////////////
UInt32 plDSoundBuffer::BytePosToMSecs( UInt32 bytePos ) const UInt32 plDSoundBuffer::BytePosToMSecs(UInt32 bytePos) const
{ {
return (UInt32)(bytePos * 1000 / (hsScalar)fBufferDesc->fAvgBytesPerSec); return (UInt32)(bytePos / ((float)fBufferDesc->fAvgBytesPerSec / 1000.0f));
} }
//// GetBufferBytePos //////////////////////////////////////////////////////// //// GetBufferBytePos ////////////////////////////////////////////////////////

View File

@ -53,10 +53,12 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plWavFile.h" #include "plWavFile.h"
#include "../plAudible/plWinAudible.h" #include "../plAudible/plWinAudible.h"
#include "../plAudioCore/plSrtFileReader.h"
#include "../pnMessage/plEventCallbackMsg.h"
#include "../pnMessage/plSoundMsg.h"
#include "../plMessage/plSubtitleMsg.h"
#include "../plNetMessage/plNetMessage.h" #include "../plNetMessage/plNetMessage.h"
#include "../pnNetCommon/plNetApp.h" #include "../pnNetCommon/plNetApp.h"
#include "../pnMessage/plSoundMsg.h"
#include "../pnMessage/plEventCallbackMsg.h"
#include "../plPipeline/plPlates.h" #include "../plPipeline/plPlates.h"
#include "../plStatusLog/plStatusLog.h" #include "../plStatusLog/plStatusLog.h"
@ -108,6 +110,23 @@ void plWin32Sound::IFreeBuffers( void )
void plWin32Sound::Update() void plWin32Sound::Update()
{ {
plSoundBuffer* buf = GetDataBuffer();
if (buf != nullptr) {
plSrtFileReader* srtReader = buf->GetSrtReader();
if (srtReader != nullptr) {
uint32_t currentTimeMs = (uint32_t)(GetActualTimeSec() * 1000.0f);
if (currentTimeMs <= srtReader->GetLastEntryEndTime()) {
while (plSrtEntry* nextEntry = srtReader->GetNextEntryStartingBeforeTime(currentTimeMs)) {
if (plgAudioSys::AreSubtitlesEnabled()) {
// add a plSubtitleMsg to go... to whoever is listening (probably the KI)
plSubtitleMsg* msg = new plSubtitleMsg(nextEntry->GetSubtitleText(), nextEntry->GetSpeakerName());
msg->Send();
}
}
}
}
}
plSound::Update(); plSound::Update();
} }
@ -120,6 +139,17 @@ void plWin32Sound::IActuallyPlay( void )
{ {
if (fDSoundBuffer && plgAudioSys::Active() ) if (fDSoundBuffer && plgAudioSys::Active() )
{ {
if (!fReallyPlaying && fSynchedStartTimeSec > 0) {
// advance past any subtitles that would end before the synched start time
// not sure when this actually happens...
plSoundBuffer* buf = GetDataBuffer();
if (buf != nullptr) {
plSrtFileReader* srtReader = buf->GetSrtReader();
if (srtReader != nullptr) {
srtReader->AdvanceToTime(fSynchedStartTimeSec * 1000.0);
}
}
}
// Sometimes base/derived classes can be annoying // Sometimes base/derived classes can be annoying
IDerivedActuallyPlay(); IDerivedActuallyPlay();

View File

@ -455,21 +455,24 @@ void plWin32StreamingSound::IActuallyStop()
unsigned plWin32StreamingSound::GetByteOffset() unsigned plWin32StreamingSound::GetByteOffset()
{ {
if(fDataStream && fDSoundBuffer) if (fDataStream && fDSoundBuffer)
{ {
UInt32 totalSize = fDataStream->GetDataSize();
UInt32 bytesRemaining = fDataStream->NumBytesLeft();
unsigned bytesQueued = fDSoundBuffer->BuffersQueued() * STREAM_BUFFER_SIZE; unsigned bytesQueued = fDSoundBuffer->BuffersQueued() * STREAM_BUFFER_SIZE;
unsigned offset = fDSoundBuffer->GetByteOffset(); unsigned offset = fDSoundBuffer->GetByteOffset();
long byteoffset = ((fDataStream->GetDataSize() - fDataStream->NumBytesLeft()) - bytesQueued) + offset; long byteoffset = ((totalSize - bytesRemaining) - bytesQueued) + offset;
return byteoffset < 0 ? fDataStream->GetDataSize() - abs(byteoffset) : byteoffset; return byteoffset < 0 ? totalSize - std::abs(byteoffset) : byteoffset;
} }
return 0; return 0;
} }
float plWin32StreamingSound::GetActualTimeSec() float plWin32StreamingSound::GetActualTimeSec()
{ {
if(fDataStream && fDSoundBuffer) if (fDataStream && fDSoundBuffer)
return fDSoundBuffer->BytePosToMSecs(fDataStream->NumBytesLeft()) / 1000.0f; return fDSoundBuffer->BytePosToMSecs(this->GetByteOffset()) / 1000.0f;
return 0.0f; return 0.0f;
} }

View File

@ -45,9 +45,11 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "hsStream.h" #include "hsStream.h"
#include "hsUtils.h" #include "hsUtils.h"
#include <cstring>
#include "plgDispatch.h" #include "plgDispatch.h"
#include "hsResMgr.h" #include "hsResMgr.h"
#include "plSrtFileReader.h"
#include "../pnMessage/plRefMsg.h" #include "../pnMessage/plRefMsg.h"
#include "../plFile/plFileUtils.h" #include "../plFile/plFileUtils.h"
#include "../plFile/hsFiles.h" #include "../plFile/hsFiles.h"
@ -117,20 +119,35 @@ static void LoadCallback(void *)
else else
{ {
plAudioFileReader *reader = nil; plAudioFileReader *reader = nil;
plSrtFileReader* srtReader = nullptr;
while(plSoundBuffer *buffer = templist.Head()) while(plSoundBuffer *buffer = templist.Head())
{ {
if(buffer->GetData()) if(buffer->GetData())
{ {
reader = CreateReader(true, buffer->GetFileName(), buffer->GetAudioReaderType(), buffer->GetReaderSelect()); const char* srcFilename = buffer->GetFileName();
reader = CreateReader(true, srcFilename, buffer->GetAudioReaderType(), buffer->GetReaderSelect());
if( reader ) if( reader )
{ {
unsigned readLen = buffer->GetAsyncLoadLength() ? buffer->GetAsyncLoadLength() : buffer->GetDataLength(); unsigned readLen = buffer->GetAsyncLoadLength() ? buffer->GetAsyncLoadLength() : buffer->GetDataLength();
reader->Read( readLen, buffer->GetData() ); reader->Read( readLen, buffer->GetData() );
buffer->SetAudioReader(reader); // give sound buffer reader, since we may need it later buffer->SetAudioReader(reader); // give sound buffer reader, since we may need it later
plSrtFileReader* srtReader = buffer->GetSrtReader();
if (srtReader != nullptr && (strcmp(srtReader->GetCurrentAudioFileName(), srcFilename) == 0)) {
// same file we were playing before, so start the SRT feed over instead of deleting and reloading
srtReader->StartOver();
} else {
std::unique_ptr<plSrtFileReader> newSrtFileReader(new plSrtFileReader(srcFilename));
if (newSrtFileReader->ReadFile())
buffer->SetSrtReader(newSrtFileReader.release());
}
} }
else else
{
buffer->SetError(); buffer->SetError();
}
} }
templist.Unlink(buffer); templist.Unlink(buffer);
@ -194,6 +211,8 @@ plSoundBuffer::~plSoundBuffer()
ASSERT(!link.IsLinked()); ASSERT(!link.IsLinked());
delete [] fFileName; delete [] fFileName;
UnLoad(); UnLoad();
delete fSrtReader;
} }
void plSoundBuffer::IInitBuffer() void plSoundBuffer::IInitBuffer()
@ -206,6 +225,7 @@ void plSoundBuffer::IInitBuffer()
fFlags = 0; fFlags = 0;
fDataRead = 0; fDataRead = 0;
fReader = nil; fReader = nil;
fSrtReader = nullptr;
fLoaded = 0; fLoaded = 0;
fLoading = false; fLoading = false;
fHeader.fFormatTag = 0; fHeader.fFormatTag = 0;
@ -458,6 +478,12 @@ void plSoundBuffer::SetLoaded(bool loaded)
fLoaded = loaded; fLoaded = loaded;
} }
void plSoundBuffer::SetSrtReader(plSrtFileReader* reader)
{
delete fSrtReader;
fSrtReader = reader;
}
/***************************************************************************** /*****************************************************************************
* *

View File

@ -61,6 +61,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
class plUnifiedTime; class plUnifiedTime;
class plAudioFileReader; class plAudioFileReader;
class plSrtFileReader;
class plSoundBuffer : public hsKeyedObject class plSoundBuffer : public hsKeyedObject
{ {
public: public:
@ -118,6 +119,8 @@ public:
plAudioFileReader * GetAudioReader(); // transfers ownership to caller plAudioFileReader * GetAudioReader(); // transfers ownership to caller
void SetAudioReader(plAudioFileReader *reader); void SetAudioReader(plAudioFileReader *reader);
void SetLoaded(bool loaded); void SetLoaded(bool loaded);
plSrtFileReader* GetSrtReader() const { return fSrtReader; } // does not transfer ownership
void SetSrtReader(plSrtFileReader* reader);
plAudioFileReader::StreamType GetAudioReaderType() { return fStreamType; } plAudioFileReader::StreamType GetAudioReaderType() { return fStreamType; }
unsigned GetAsyncLoadLength() { return fAsyncLoadLength ? fAsyncLoadLength : fDataLength; } unsigned GetAsyncLoadLength() { return fAsyncLoadLength ? fAsyncLoadLength : fDataLength; }
@ -149,6 +152,7 @@ protected:
bool fError; bool fError;
plAudioFileReader * fReader; plAudioFileReader * fReader;
plSrtFileReader* fSrtReader;
UInt8 * fData; UInt8 * fData;
plWAVHeader fHeader; plWAVHeader fHeader;
UInt32 fDataLength; UInt32 fDataLength;

View File

@ -0,0 +1,196 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plSrtFileReader.h"
#include "hsStream.h"
#include "../plStatusLog/plStatusLog.h"
#include "../pnUtils/pnUtils.h"
#include <regex>
static const std::regex speakerTextRegex("^((([\\w.]+(\\s\\w+)?):) )?(.*)");
static const std::regex timingsRegex("^(\\d{2}):(\\d{2}):(\\d{2}),(\\d{3}) --> (\\d{2}):(\\d{2}):(\\d{2}),(\\d{3})$");
bool plSrtFileReader::ReadFile()
{
wchar path[MAX_PATH];
StrPrintf(path, arrsize(path), L"sfx\\%S", fAudioFileName);
PathSetExtension(path, path, L".sub", arrsize(path));
if (PathDoesFileExist(path)) {
// read sets of SRT data until end of file
hsUNIXStream srtFileStream;
// if file exists and was opened successfully
if (srtFileStream.Open(path, L"r")) {
plStatusLog::AddLineS("audio.log", "Successfully opened subtitle file %S", path);
uint32_t subtitleNumber = 0;
uint32_t subtitleStartTimeMs = 0;
uint32_t subtitleEndTimeMs = 0;
char line[4096];
std::string speakerName;
std::string subtitleText;
std::cmatch matches;
for (unsigned int lnCounter = 0; !srtFileStream.AtEnd(); lnCounter++) {
if (lnCounter % 4 == 0 && srtFileStream.ReadLn(line)) {
subtitleNumber = std::stoul(line);
} else if (lnCounter % 4 == 1 && srtFileStream.ReadLn(line)) {
if (std::regex_match(line, matches, timingsRegex)) {
if (matches.size() < 9) {
// add error message and ensure this subtitle line won't be added to the entries
plStatusLog::AddLineS("audio.log", plStatusLog::kRed, " Subtitle timings '%s' are formatted incorrectly.", line);
subtitleNumber = 0;
}
else {
// matches[0] is the entire match, we don't do anything with it
// matches[1] is the first group -- the start hour number
subtitleStartTimeMs += std::stoul(matches[1].str()) * 3600000;
// matches[2] is the second group -- the start minute number
subtitleStartTimeMs += std::stoul(matches[2].str()) * 60000;
// matches[3] is the third group -- the start seconds number
subtitleStartTimeMs += std::stoul(matches[3].str()) * 1000;
// matches[4] is the fourth group -- the start milliseconds number
subtitleStartTimeMs += std::stoul(matches[4].str());
// matches[5] is the fifth group -- the end hour number
subtitleEndTimeMs += std::stoul(matches[5].str()) * 3600000;
// matches[6] is the sixth group -- the end minute number
subtitleEndTimeMs += std::stoul(matches[6].str()) * 60000;
// matches[7] is the seventh group -- the end seconds number
subtitleEndTimeMs += std::stoul(matches[7].str()) * 1000;
// matches[8] is the eighth group -- the end milliseconds number
subtitleEndTimeMs += std::stoul(matches[8].str());
}
}
} else if (lnCounter % 4 == 2 && srtFileStream.ReadLn(line)) {
if (std::regex_match(line, matches, speakerTextRegex)) {
if (matches.size() < 5) {
// add error message and ensure this subtitle line won't be added to the entries
plStatusLog::AddLineS("audio.log", plStatusLog::kRed, " Subtitle text and/or speaker name '%s' are formatted incorrectly.", line);
subtitleNumber = 0;
} else {
// matches[0] is the entire match, we don't do anything with it
// matches[2] is the second group (the optional subtitle speaker with colon but no space at the end)
speakerName = matches[2];
// matches[5] is the fourth group (the subtitle text)
subtitleText = matches[5];
}
}
} else if (lnCounter % 4 == 3 && subtitleNumber > 0 && subtitleStartTimeMs >= 0 && subtitleEndTimeMs >= 0 && !subtitleText.empty()) {
// entry is complete, add to the queue and reset our temp variables
if (!speakerName.empty())
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText), std::move(speakerName)));
else
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText)));
subtitleNumber = 0;
subtitleStartTimeMs = 0;
subtitleEndTimeMs = 0;
subtitleText.clear();
speakerName.clear();
}
}
if (subtitleNumber > 0 && subtitleStartTimeMs >= 0 && subtitleEndTimeMs >= 0 && !subtitleText.empty()) {
// enqueue the last subtitle from the file if we didn't have an extra blank line at the end
if (!speakerName.empty())
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText), std::move(speakerName)));
else
fEntries.emplace_back(plSrtEntry(subtitleNumber, subtitleStartTimeMs, subtitleEndTimeMs, std::move(subtitleText)));
}
return true;
}
}
return false;
}
void plSrtFileReader::AdvanceToTime(uint32_t timeMs)
{
while (fCurrentEntryIndex < fEntries.size() && fEntries.at(fCurrentEntryIndex).GetEndTimeMs() <= timeMs) {
fCurrentEntryIndex++;
}
}
plSrtEntry* plSrtFileReader::GetNextEntryStartingBeforeTime(uint32_t timeMs)
{
if (fCurrentEntryIndex < fEntries.size()) {
plSrtEntry& nextEntry = fEntries.at(fCurrentEntryIndex);
if (nextEntry.GetStartTimeMs() <= timeMs) {
fCurrentEntryIndex++;
return &nextEntry;
}
}
return nullptr;
}
plSrtEntry* plSrtFileReader::GetNextEntryEndingBeforeTime(uint32_t timeMs)
{
if (fCurrentEntryIndex < fEntries.size()) {
plSrtEntry& nextEntry = fEntries.at(fCurrentEntryIndex);
if (nextEntry.GetEndTimeMs() <= timeMs) {
fCurrentEntryIndex++;
return &nextEntry;
}
}
return nullptr;
}
uint32_t plSrtFileReader::GetLastEntryEndTime()
{
if (!fEntries.empty()) {
return fEntries.back().GetEndTimeMs();
}
return 0;
}

View File

@ -0,0 +1,108 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plSrtFileReader - Class for reading an SRT format file and //
// storing the read entries for access later //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plSrtFileReader_h
#define _plSrtFileReader_h
#include "hsTypes.h"
#include "../pnUtils/pnUtils.h"
#include <cstdint>
#include <vector>
class plSrtEntry
{
public:
plSrtEntry(uint32_t entryNum, uint32_t startTimeMs, uint32_t endTimeMs, std::string subtitleText, std::string speakerName)
: fEntryNum(entryNum), fStartTimeMs(startTimeMs), fEndTimeMs(endTimeMs), fSubtitleText(std::move(subtitleText)),
fSpeakerName(std::move(speakerName)) { }
plSrtEntry(uint32_t entryNum, uint32_t startTimeMs, uint32_t endTimeMs, std::string subtitleText)
: fEntryNum(entryNum), fStartTimeMs(startTimeMs), fEndTimeMs(endTimeMs), fSubtitleText(std::move(subtitleText)) { }
std::string GetSubtitleText() const { return fSubtitleText; }
std::string GetSpeakerName() const { return fSpeakerName; }
uint32_t GetStartTimeMs() const { return fStartTimeMs; }
uint32_t GetEndTimeMs() const { return fEndTimeMs; }
protected:
uint32_t fEntryNum;
uint32_t fStartTimeMs;
uint32_t fEndTimeMs;
std::string fSubtitleText;
std::string fSpeakerName;
};
class plSrtFileReader
{
public:
plSrtFileReader(const char* audioFileName)
: fAudioFileName(StrDup(audioFileName)), fCurrentEntryIndex(0) { }
virtual ~plSrtFileReader() { delete[] fAudioFileName; }
bool ReadFile();
void StartOver() { fCurrentEntryIndex = 0; }
const char* GetCurrentAudioFileName() const { return fAudioFileName; }
void AdvanceToTime(uint32_t timeMs);
plSrtEntry* GetNextEntryStartingBeforeTime(uint32_t timeMs);
plSrtEntry* GetNextEntryEndingBeforeTime(uint32_t timeMs);
uint32_t GetLastEntryEndTime();
protected:
const char* fAudioFileName;
std::vector<plSrtEntry> fEntries;
uint32_t fCurrentEntryIndex;
};
#endif //_plSrtFileReader_h

View File

@ -313,7 +313,7 @@ hsBool plAnimStage::ISendNotify(UInt32 notifyMask, UInt32 notifyType, plArmature
int stageNum = genBrain ? genBrain->GetStageNum(this) : -1; int stageNum = genBrain ? genBrain->GetStageNum(this) : -1;
msg->AddMultiStageEvent(stageNum, notifyType, armature->GetTarget(0)->GetKey()); msg->AddMultiStageEvent(stageNum, notifyType, armature->GetTarget(0)->GetKey());
if (! genBrain->RelayNotifyMsg(msg) ) if (stageNum < 0 || !genBrain || !genBrain->RelayNotifyMsg(msg) )
{ {
msg->UnRef(); // couldn't send; destroy... msg->UnRef(); // couldn't send; destroy...
} }

View File

@ -866,8 +866,8 @@ void plArmatureMod::SpawnAt(int spawnNum, double time)
ci->SetTransform(l2w, w2l); ci->SetTransform(l2w, w2l);
ci->FlushTransform(); ci->FlushTransform();
if (plVirtualCam1::Instance()) if (IsLocalAvatar() && plVirtualCam1::Instance())
plVirtualCam1::Instance()->SetCutNextTrans(); plVirtualCam1::Instance()->SetCutNext();
if (GetFollowerParticleSystemSO()) if (GetFollowerParticleSystemSO())
{ {

View File

@ -234,7 +234,9 @@ public:
virtual void PanicLink(hsBool playLinkOutAnim = true); virtual void PanicLink(hsBool playLinkOutAnim = true);
virtual void PersonalLink(); virtual void PersonalLink();
virtual bool ToggleDontPanicLinkFlag() { fDontPanicLink = fDontPanicLink ? false : true; return fDontPanicLink; } bool ToggleDontPanicLinkFlag() { fDontPanicLink = fDontPanicLink ? false : true; return fDontPanicLink; }
void SetDontPanicLinkFlag(bool value) { fDontPanicLink = value; }
int GetBrainCount(); int GetBrainCount();
plArmatureBrain *GetNextBrain(plArmatureBrain *brain); plArmatureBrain *GetNextBrain(plArmatureBrain *brain);

View File

@ -326,7 +326,7 @@ bool plAvBrainClimb::IProcessExitStage(double time, float elapsed)
float curBlend = ai->GetBlend(); float curBlend = ai->GetBlend();
if(curBlend > .99) // reached peak strength if(fCurStage && curBlend > .99) // reached peak strength
{ {
fCurStage->Detach(fAvMod); // remove the (now completely masked) underlying anim fCurStage->Detach(fAvMod); // remove the (now completely masked) underlying anim
fCurStage = nil; fCurStage = nil;
@ -703,8 +703,8 @@ void plAvBrainClimb::ICalcProbeLengths()
{ {
// we assume that the up and down climbs go the same distance; // we assume that the up and down climbs go the same distance;
// same for the left and right climbs // same for the left and right climbs
plAGAnim *up = fAvMod->FindCustomAnim("ClimbUp"); plAGAnim *up = fAvMod->FindCustomAnim("WallClimbUp");
plAGAnim *left = fAvMod->FindCustomAnim("ClimbLeft"); plAGAnim *left = fAvMod->FindCustomAnim("WallClimbLeft");
hsMatrix44 upMove, leftMove; hsMatrix44 upMove, leftMove;

View File

@ -75,6 +75,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "../plInputCore/plInputDevice.h" #include "../plInputCore/plInputDevice.h"
#include "../plMath/plRandom.h" #include "../plMath/plRandom.h"
#include "../plPipeline/plDebugText.h" #include "../plPipeline/plDebugText.h"
#include "../plNetClient/plNetClientMgr.h"
#include "../plNetClient/plNetLinkingMgr.h" #include "../plNetClient/plNetLinkingMgr.h"
#include "../plMessage/plAvatarMsg.h" #include "../plMessage/plAvatarMsg.h"
@ -494,12 +495,20 @@ hsBool plAvBrainHuman::IHandleClimbMsg(plClimbMsg *msg)
bool isStartClimb = msg->fCommand == plClimbMsg::kStartClimbing; bool isStartClimb = msg->fCommand == plClimbMsg::kStartClimbing;
if(isStartClimb) if(isStartClimb)
{ {
// let's build a seek task to get us to the attach point // Warp the player to the Seekpoint
plKey seekTarget = msg->fTarget; plSceneObject *avatarObj = plSceneObject::ConvertNoRef(plNetClientMgr::GetInstance()->GetLocalPlayer());
plAvTaskSeek *seekTask = TRACKED_NEW plAvTaskSeek(seekTarget); plSceneObject *obj = plSceneObject::ConvertNoRef(msg->fTarget->ObjectIsLoaded());
QueueTask(seekTask); plArmatureMod *localAvatar = plAvatarMgr::GetInstance()->GetLocalAvatar();
plArmatureMod *climbAvatar = plArmatureMod::ConvertNoRef(fArmature);
if (climbAvatar == localAvatar) // is it our avatar who has to seek?
{
hsMatrix44 target = obj->GetLocalToWorld();
plWarpMsg *warp = TRACKED_NEW plWarpMsg(NULL, avatarObj->GetKey(), plWarpMsg::kFlushTransform, target);
warp->SetBCastFlag(plMessage::kNetPropagate);
plgDispatch::MsgSend(warp);
}
// now a brain task to start the actual climb. // build the Climb brain
plAvBrainClimb::Mode startMode; plAvBrainClimb::Mode startMode;
switch(msg->fDirection) switch(msg->fDirection)
{ {
@ -515,10 +524,11 @@ hsBool plAvBrainHuman::IHandleClimbMsg(plClimbMsg *msg)
case plClimbMsg::kRight: case plClimbMsg::kRight:
startMode = plAvBrainClimb::kMountingRight; startMode = plAvBrainClimb::kMountingRight;
break; break;
default:
break;
} }
plAvBrainClimb *brain = TRACKED_NEW plAvBrainClimb(startMode); plAvBrainClimb *brain = TRACKED_NEW plAvBrainClimb(startMode);
plAvTaskBrain *brainTask = TRACKED_NEW plAvTaskBrain(brain); climbAvatar->PushBrain(brain);
QueueTask(brainTask);
} }
// ** potentially controversial: // ** potentially controversial:
// It's fairly easy for a human brain to hit a climb trigger - like when falling off a wall. // It's fairly easy for a human brain to hit a climb trigger - like when falling off a wall.

View File

@ -1003,7 +1003,7 @@ void plClothingOutfit::IUpdate()
} }
} }
void plClothingOutfit::WearDefaultClothing() void plClothingOutfit::WearDefaultClothing(hsBool broadcast)
{ {
StripAccessories(); StripAccessories();
@ -1041,9 +1041,14 @@ void plClothingOutfit::WearDefaultClothing()
} }
} }
} }
if (broadcast) {
fSynchClients = true;
ForceUpdate(true);
}
} }
void plClothingOutfit::WearDefaultClothingType(UInt32 clothingType) void plClothingOutfit::WearDefaultClothingType(UInt32 clothingType, hsBool broadcast)
{ {
plClothingMgr *cMgr = plClothingMgr::GetClothingMgr(); plClothingMgr *cMgr = plClothingMgr::GetClothingMgr();
hsTArray<plClothingItem *> items; hsTArray<plClothingItem *> items;
@ -1072,6 +1077,11 @@ void plClothingOutfit::WearDefaultClothingType(UInt32 clothingType)
break; break;
} }
} }
if (broadcast) {
fSynchClients = true;
ForceUpdate(true);
}
} }
void plClothingOutfit::WearMaintainerOutfit() void plClothingOutfit::WearMaintainerOutfit()

View File

@ -199,8 +199,8 @@ public:
hsBool DirtySynchState(const char* SDLStateName, UInt32 synchFlags); hsBool DirtySynchState(const char* SDLStateName, UInt32 synchFlags);
void StripAccessories(); void StripAccessories();
void WearDefaultClothing(); void WearDefaultClothing(hsBool broadcast = false);
void WearDefaultClothingType(UInt32 clothingType); void WearDefaultClothingType(UInt32 clothingType, hsBool broadcast = false);
void WearMaintainerOutfit(); void WearMaintainerOutfit();
void WearRandomOutfit(); void WearRandomOutfit();
void RemoveMaintainerOutfit(); void RemoveMaintainerOutfit();

View File

@ -408,7 +408,7 @@ void plMouseDevice::CreateCursor( char* cursor )
fCursor->SetPosition( 0, 0, 0 ); fCursor->SetPosition( 0, 0, 0 );
IUpdateCursorSize(); IUpdateCursorSize();
fCursor->SetVisible( true ); fCursor->SetVisible(!bCursorHidden);
fCursor->SetOpacity( fOpacity ); fCursor->SetOpacity( fOpacity );
} }
@ -481,8 +481,8 @@ void plMouseDevice::SetCursorY(hsScalar y)
void plMouseDevice::HideCursor(hsBool override) void plMouseDevice::HideCursor(hsBool override)
{ {
if( fInstance->fCursor != nil ) if (fInstance && fInstance->fCursor)
fInstance->fCursor->SetVisible( false ); fInstance->fCursor->SetVisible(false);
plMouseDevice::bCursorOverride = (override != 0); plMouseDevice::bCursorOverride = (override != 0);
plMouseDevice::bCursorHidden = true; plMouseDevice::bCursorHidden = true;
@ -499,9 +499,11 @@ void plMouseDevice::ShowCursor(hsBool override)
plMouseDevice::bCursorHidden = false; plMouseDevice::bCursorHidden = false;
plMouseDevice::bCursorOverride = false; plMouseDevice::bCursorOverride = false;
if( fInstance->fCursor == nil ) if (fInstance) {
fInstance->CreateCursor( fInstance->fCursorID ); if (!fInstance->fCursor)
fInstance->fCursor->SetVisible( true ); fInstance->CreateCursor(fInstance->fCursorID);
fInstance->fCursor->SetVisible(true);
}
} }
void plMouseDevice::NewCursor(char* cursor) void plMouseDevice::NewCursor(char* cursor)
@ -510,9 +512,6 @@ void plMouseDevice::NewCursor(char* cursor)
fInstance->CreateCursor(cursor); fInstance->CreateCursor(cursor);
fInstance->SetCursorX(fInstance->GetCursorX()); fInstance->SetCursorX(fInstance->GetCursorX());
fInstance->SetCursorY(fInstance->GetCursorY()); fInstance->SetCursorY(fInstance->GetCursorY());
if (!plMouseDevice::bCursorHidden)
fInstance->fCursor->SetVisible( true );
} }
void plMouseDevice::SetCursorOpacity( hsScalar opacity ) void plMouseDevice::SetCursorOpacity( hsScalar opacity )

View File

@ -253,15 +253,13 @@ void plInputInterfaceMgr::IUpdateCursor( Int32 newCursor )
{ {
char* mouseCursorResID; char* mouseCursorResID;
if (newCursor == plInputInterface::kCursorHidden) {
fCurrentCursor = newCursor;
if( fCurrentCursor == plInputInterface::kCursorHidden )
plMouseDevice::HideCursor(); plMouseDevice::HideCursor();
else } else {
{ if (fCurrentCursor == plInputInterface::kCursorHidden)
plMouseDevice::ShowCursor(); plMouseDevice::ShowCursor();
switch( fCurrentCursor ) switch(newCursor)
{ {
case plInputInterface::kCursorUp: mouseCursorResID = CURSOR_UP; break; case plInputInterface::kCursorUp: mouseCursorResID = CURSOR_UP; break;
case plInputInterface::kCursorLeft: mouseCursorResID = CURSOR_LEFT; break; case plInputInterface::kCursorLeft: mouseCursorResID = CURSOR_LEFT; break;
@ -286,12 +284,12 @@ void plInputInterfaceMgr::IUpdateCursor( Int32 newCursor )
case plInputInterface::kCursorHand: mouseCursorResID = CURSOR_HAND; break; case plInputInterface::kCursorHand: mouseCursorResID = CURSOR_HAND; break;
case plInputInterface::kCursorUpward: mouseCursorResID = CURSOR_UPWARD; break; case plInputInterface::kCursorUpward: mouseCursorResID = CURSOR_UPWARD; break;
default: mouseCursorResID = CURSOR_OPEN; break; default: mouseCursorResID = CURSOR_OPEN; break;
} }
plMouseDevice::NewCursor(mouseCursorResID);
plMouseDevice::NewCursor( mouseCursorResID );
} }
fCurrentCursor = newCursor;
} }
//// IEval /////////////////////////////////////////////////////////////////// //// IEval ///////////////////////////////////////////////////////////////////

View File

@ -133,6 +133,10 @@ REGISTER_CREATABLE( plSpawnModMsg );
REGISTER_CREATABLE( plSpawnRequestMsg ); REGISTER_CREATABLE( plSpawnRequestMsg );
#include "plSubtitleMsg.h"
REGISTER_CREATABLE(plSubtitleMsg);
#include "plNodeCleanupMsg.h" #include "plNodeCleanupMsg.h"
REGISTER_CREATABLE( plNodeCleanupMsg ); REGISTER_CREATABLE( plNodeCleanupMsg );

View File

@ -0,0 +1,82 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plSubtitleMsg_inc
#define plSubtitleMsg_inc
#include "../pnMessage/plMessage.h"
/** Show subtitle text for in-game audio */
class plSubtitleMsg : public plMessage
{
protected:
std::string fText;
std::string fSpeaker;
public:
plSubtitleMsg() : plMessage()
{
SetBCastFlag(plMessage::kBCastByExactType);
}
plSubtitleMsg(std::string msgText) : plMessage(), fText(std::move(msgText))
{
SetBCastFlag(plMessage::kBCastByExactType);
}
plSubtitleMsg(std::string msgText, std::string msgSpeaker) : plMessage(), fText(std::move(msgText)),
fSpeaker(std::move(msgSpeaker))
{
SetBCastFlag(plMessage::kBCastByExactType);
}
CLASSNAME_REGISTER(plSubtitleMsg);
GETINTERFACE_ANY(plSubtitleMsg, plMessage);
void Read(hsStream*, hsResMgr*) override { FATAL("no"); }
void Write(hsStream*, hsResMgr*) override { FATAL("no"); }
std::string GetText() const { return fText; }
std::string GetSpeaker() const { return fSpeaker; }
};
#endif // plSubtitleMsg_inc

View File

@ -504,25 +504,56 @@ bool plNetLinkingMgr::IProcessVaultNotifyMsg(plVaultNotifyMsg* msg)
return false; return false;
} }
if (cVaultLink != nil) if (cVaultLink != nil) {
{ // Verify that if the Age vault already exists that it matches the requested
// This is something that Cyan does... >.< // deferred link. If it doesn't exist, well, I hope you're happy with the result.
// It's very useful though...
VaultAgeLinkNode accLink(cVaultLink); VaultAgeLinkNode accLink(cVaultLink);
accLink.CopyTo(cur); if (RelVaultNode* rvnInfo = cVaultLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
if (RelVaultNode* rvnInfo = cVaultLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) plAgeInfoStruct dest;
{
VaultAgeInfoNode accInfo(rvnInfo); VaultAgeInfoNode accInfo(rvnInfo);
accInfo.CopyTo(cur->GetAgeInfo()); accInfo.CopyTo(&dest);
if (!dest.IsEqualTo(fDeferredLink->GetAgeLink()->GetAgeInfo())) {
hsLogEntry(
plNetClientMgr::GetInstance()->DebugMsg(
"Waiting for a deferred link to '%s' but got AgeInfo for '%s' instead.",
fDeferredLink->GetAgeLink()->AsStdString().c_str(),
dest.AsStdString().c_str()
);
);
rvnInfo->DecRef();
return false;
}
rvnInfo->DecRef(); rvnInfo->DecRef();
} }
// If we're still here, that means the links match. Set the vault copy as our current
// AgeLink and AgeInfo. Note this mainly copies the AgeInfo.
accLink.CopyTo(cur);
hsLogEntry(
plNetClientMgr::GetInstance()->DebugMsg(
"Performing deferred link to '%s'",
cur->AsStdString().c_str()
);
);
// Steals fDeferredLink
IDoLink(fDeferredLink); IDoLink(fDeferredLink);
fDeferredLink = nil; fDeferredLink = nil;
return true;
cVaultLink->DecRef(); cVaultLink->DecRef();
}
return true;
} else {
hsLogEntry(
plNetClientMgr::GetInstance()->ErrorMsg(
"Waiting for a deferred link to '%s' but got a garbage link?",
fDeferredLink->GetAgeLink()->AsStdString().c_str()
)
);
}
return false; return false;
} }

View File

@ -1328,9 +1328,9 @@ void plPXPhysical::GetSyncState(hsPoint3& pos, hsQuat& rot, hsVector3& linV, hsV
void plPXPhysical::SetSyncState(hsPoint3* pos, hsQuat* rot, hsVector3* linV, hsVector3* angV) void plPXPhysical::SetSyncState(hsPoint3* pos, hsQuat* rot, hsVector3* linV, hsVector3* angV)
{ {
bool initialSync = plNetClientApp::GetInstance()->IsLoadingInitialAgeState() && bool isLoading = plNetClientApp::GetInstance()->IsLoadingInitialAgeState();
plNetClientApp::GetInstance()->GetJoinOrder() == 0; bool isFirstIn = plNetClientApp::GetInstance()->GetJoinOrder() == 0;
bool initialSync = isLoading && isFirstIn;
// If the physical has fallen out of the sim, and this is initial age state, and we're // If the physical has fallen out of the sim, and this is initial age state, and we're
// the first person in, reset it to the original position. (ie, prop the default state // the first person in, reset it to the original position. (ie, prop the default state
// we've got right now) // we've got right now)
@ -1350,6 +1350,13 @@ void plPXPhysical::SetSyncState(hsPoint3* pos, hsQuat* rot, hsVector3* linV, hsV
SetLinearVelocitySim(*linV); SetLinearVelocitySim(*linV);
if (angV) if (angV)
SetAngularVelocitySim(*angV); SetAngularVelocitySim(*angV);
// If we're loading the age, then we should ensure the objects stay asleep if they're supposed to be asleep.
// NOTE: We should only do this if the objects are not at their initial locations. Otherwise, they might
// sleep inside each other and explode or float randomly in midair
if (isLoading && GetProperty(plSimulationInterface::kStartInactive) && !fActor->readBodyFlag(NX_BF_KINEMATIC)) {
if (!pos && !rot)
fActor->putToSleep();
}
SendNewLocation(false, true); SendNewLocation(false, true);
} }

View File

@ -536,7 +536,7 @@ inline plKeyImp* IFindKeyLocalized(const plUoid& uoid, plRegistryPageNode* page)
const char* objectName = uoid.GetObjectName(); const char* objectName = uoid.GetObjectName();
// If we're running localized, try to find a localized version first // If we're running localized, try to find a localized version first
if (plLocalization::IsLocalized()) if (objectName != nullptr && plLocalization::IsLocalized())
{ {
char localName[256]; char localName[256];
if (plLocalization::GetLocalized(objectName, localName)) if (plLocalization::GetLocalized(objectName, localName))
@ -1299,7 +1299,7 @@ void plResManager::PageInAge(const char *age)
hsBool plResManager::VerifyPages() hsBool plResManager::VerifyPages()
{ {
hsTArray<plRegistryPageNode*> invalidPages, newerPages; PageSet invalidPages, newerPages;
// Step 1: verify major/minor version changes // Step 1: verify major/minor version changes
if (plResMgrSettings::Get().GetFilterNewerPageVersions() || if (plResMgrSettings::Get().GetFilterNewerPageVersions() ||
@ -1313,7 +1313,7 @@ hsBool plResManager::VerifyPages()
if (page->GetPageCondition() == kPageTooNew && plResMgrSettings::Get().GetFilterNewerPageVersions()) if (page->GetPageCondition() == kPageTooNew && plResMgrSettings::Get().GetFilterNewerPageVersions())
{ {
newerPages.Append(page); newerPages.insert(page);
fAllPages.erase(page); fAllPages.erase(page);
} }
else if ( else if (
@ -1321,21 +1321,21 @@ hsBool plResManager::VerifyPages()
page->GetPageCondition() == kPageOutOfDate) page->GetPageCondition() == kPageOutOfDate)
&& plResMgrSettings::Get().GetFilterOlderPageVersions()) && plResMgrSettings::Get().GetFilterOlderPageVersions())
{ {
invalidPages.Append(page); invalidPages.insert(page);
fAllPages.erase(page); fAllPages.erase(page);
} }
} }
} }
// Handle all our invalid pages now // Handle all our invalid pages now
if (invalidPages.GetCount() > 0) if (!invalidPages.empty())
{ {
if (!IDeleteBadPages(invalidPages, false)) if (!IDeleteBadPages(invalidPages, false))
return false; return false;
} }
// Warn about newer pages // Warn about newer pages
if (newerPages.GetCount() > 0) if (!newerPages.empty())
{ {
if (!IWarnNewerPages(newerPages)) if (!IWarnNewerPages(newerPages))
return false; return false;
@ -1343,22 +1343,35 @@ hsBool plResManager::VerifyPages()
// Step 2 of verification: make sure no sequence numbers conflict // Step 2 of verification: make sure no sequence numbers conflict
PageSet::iterator it = fAllPages.begin(); PageSet::iterator it = fAllPages.begin();
for (; it != fAllPages.end(); it++) for (; it != fAllPages.end();)
{ {
plRegistryPageNode* page = *it; plRegistryPageNode* page = *it;
PageSet::iterator itUp = it; PageSet::iterator itUp = it;
itUp++; itUp++;
for (; itUp != fAllPages.end(); itUp++) bool amValid = true;
for (; itUp != fAllPages.end();)
{ {
plRegistryPageNode* upPage = *itUp; plRegistryPageNode* upPage = *itUp;
if (page->GetPageInfo().GetLocation() == upPage->GetPageInfo().GetLocation()) if (page->GetPageInfo().GetLocation() == upPage->GetPageInfo().GetLocation()) {
{ invalidPages.insert(upPage);
invalidPages.Append(upPage); itUp = fAllPages.erase(itUp);
fAllPages.erase(itUp); amValid = false;
break; } else {
itUp++;
} }
} }
// Delete *all* conflicting pages, not just conflicting - 1.
// If we leave in a single conflicting page, a new conflict can trivially
// be introduced if the page we leave behind is defunct and a new version
// is later downloaded from the FileSrv.
if (!amValid) {
invalidPages.insert(page);
it = fAllPages.erase(it);
} else {
it++;
}
} }
// Redo our loaded pages list, since Verify() might force the page's keys to load or unload // Redo our loaded pages list, since Verify() might force the page's keys to load or unload
@ -1374,7 +1387,7 @@ hsBool plResManager::VerifyPages()
} }
// Handle all our conflicting pages now // Handle all our conflicting pages now
if (invalidPages.GetCount() > 0) if (!invalidPages.empty())
return IDeleteBadPages(invalidPages, true); return IDeleteBadPages(invalidPages, true);
return true; return true;
@ -1384,9 +1397,10 @@ hsBool plResManager::VerifyPages()
// Given an array of pages that are invalid (major version out-of-date or // Given an array of pages that are invalid (major version out-of-date or
// whatnot), asks the user what we should do about them. // whatnot), asks the user what we should do about them.
static void ICatPageNames(hsTArray<plRegistryPageNode*>& pages, char* buf, int bufSize) static void ICatPageNames(const std::set<plRegistryPageNode*>& pages, char* buf, int bufSize)
{ {
for (int i = 0; i < pages.GetCount(); i++) int i = 0;
for (auto it = pages.cbegin(); it != pages.cend(); ++it, ++i)
{ {
if (i >= 25) if (i >= 25)
{ {
@ -1394,7 +1408,7 @@ static void ICatPageNames(hsTArray<plRegistryPageNode*>& pages, char* buf, int b
break; break;
} }
const char* pagePath = pages[i]->GetPagePath(); const char* pagePath = (*it)->GetPagePath();
const char* pageFile = plFileUtils::GetFileName(pagePath); const char* pageFile = plFileUtils::GetFileName(pagePath);
if (strlen(buf) + strlen(pageFile) > bufSize - 5) if (strlen(buf) + strlen(pageFile) > bufSize - 5)
@ -1408,7 +1422,7 @@ static void ICatPageNames(hsTArray<plRegistryPageNode*>& pages, char* buf, int b
} }
} }
hsBool plResManager::IDeleteBadPages(hsTArray<plRegistryPageNode*>& invalidPages, hsBool conflictingSeqNums) hsBool plResManager::IDeleteBadPages(PageSet& invalidPages, hsBool conflictingSeqNums)
{ {
#ifndef PLASMA_EXTERNAL_RELEASE #ifndef PLASMA_EXTERNAL_RELEASE
if (!hsMessageBox_SuppressPrompts) if (!hsMessageBox_SuppressPrompts)
@ -1430,12 +1444,12 @@ hsBool plResManager::IDeleteBadPages(hsTArray<plRegistryPageNode*>& invalidPages
#endif // PLASMA_EXTERNAL_RELEASE #endif // PLASMA_EXTERNAL_RELEASE
// Delete 'em // Delete 'em
for (int i = 0; i < invalidPages.GetCount(); i++) for (PageSet::iterator it = invalidPages.begin(); it != invalidPages.end(); ++it)
{ {
invalidPages[i]->DeleteSource(); (*it)->DeleteSource();
delete invalidPages[i]; delete *it;
} }
invalidPages.Reset(); invalidPages.clear();
fLastFoundPage = nil; fLastFoundPage = nil;
@ -1447,7 +1461,7 @@ hsBool plResManager::IDeleteBadPages(hsTArray<plRegistryPageNode*>& invalidPages
// than the "current" one), warns the user about them but does nothing to // than the "current" one), warns the user about them but does nothing to
// them. // them.
hsBool plResManager::IWarnNewerPages(hsTArray<plRegistryPageNode*> &newerPages) hsBool plResManager::IWarnNewerPages(PageSet &newerPages)
{ {
#ifndef PLASMA_EXTERNAL_RELEASE #ifndef PLASMA_EXTERNAL_RELEASE
if (!hsMessageBox_SuppressPrompts) if (!hsMessageBox_SuppressPrompts)
@ -1465,9 +1479,9 @@ hsBool plResManager::IWarnNewerPages(hsTArray<plRegistryPageNode*> &newerPages)
// Not deleting the files, just delete them from memory // Not deleting the files, just delete them from memory
for (int i = 0; i < newerPages.GetCount(); i++) for (PageSet::iterator it = newerPages.begin(); it != newerPages.end(); ++it)
delete newerPages[i]; delete *it;
newerPages.Reset(); newerPages.clear();
fLastFoundPage = nil; fLastFoundPage = nil;

View File

@ -61,6 +61,9 @@ typedef void(*plProgressProc)(plKey key);
class plResManager : public hsResMgr class plResManager : public hsResMgr
{ {
protected:
typedef std::set<plRegistryPageNode*> PageSet;
public: public:
plResManager(); plResManager();
virtual ~plResManager(); virtual ~plResManager();
@ -194,8 +197,8 @@ protected:
void IUnloadPageKeys(plRegistryPageNode* pageNode, hsBool dontClear = false); void IUnloadPageKeys(plRegistryPageNode* pageNode, hsBool dontClear = false);
hsBool IDeleteBadPages(hsTArray<plRegistryPageNode*>& invalidPages, hsBool conflictingSeqNums); hsBool IDeleteBadPages(PageSet& invalidPages, hsBool conflictingSeqNums);
hsBool IWarnNewerPages(hsTArray<plRegistryPageNode*>& newerPages); hsBool IWarnNewerPages(PageSet& newerPages);
void ILockPages(); void ILockPages();
void IUnlockPages(); void IUnlockPages();
@ -233,7 +236,6 @@ protected:
UInt8 fPageListLock; // Number of locks on the page lists. If it's greater than zero, they can't be modified UInt8 fPageListLock; // Number of locks on the page lists. If it's greater than zero, they can't be modified
hsBool fPagesNeedCleanup; // True if something modified the page lists while they were locked. hsBool fPagesNeedCleanup; // True if something modified the page lists while they were locked.
typedef std::set<plRegistryPageNode*> PageSet;
PageSet fAllPages; // All the pages, loaded or not PageSet fAllPages; // All the pages, loaded or not
PageSet fLoadedPages; // Just the loaded pages PageSet fLoadedPages; // Just the loaded pages