| @@ -0,0 +1,69 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifdef FW_SOUND | |
| 24 | + | ||
| 25 | + | #ifndef SHOUNDCHANNEL_H | |
| 26 | + | #define SHOUNDCHANNEL_H | |
| 27 | + | ||
| 28 | + | #include "soundsource.h" | |
| 29 | + | ||
| 30 | + | // @bindclass | |
| 31 | + | class SoundChannel : public LuaObject | |
| 32 | + | { | |
| 33 | + | public: | |
| 34 | + | SoundChannel(int id) : m_id(id), m_gain(1) { } | |
| 35 | + | ||
| 36 | + | SoundSourcePtr play(const std::string& filename, float fadetime = 0, float gain = 1.0f); | |
| 37 | + | void stop(float fadetime = 0); | |
| 38 | + | void enqueue(const std::string& filename, float fadetime = 0, float gain = 1.0f); | |
| 39 | + | void enable() { setEnabled(true); } | |
| 40 | + | void disable() { setEnabled(false); } | |
| 41 | + | ||
| 42 | + | void setGain(float gain); | |
| 43 | + | float getGain() { return m_gain; } | |
| 44 | + | ||
| 45 | + | void setEnabled(bool enable); | |
| 46 | + | bool isEnabled() { return m_enabled; } | |
| 47 | + | ||
| 48 | + | int getId() { return m_id; } | |
| 49 | + | ||
| 50 | + | protected: | |
| 51 | + | void update(); | |
| 52 | + | friend class SoundManager; | |
| 53 | + | ||
| 54 | + | private: | |
| 55 | + | struct QueueEntry { | |
| 56 | + | std::string filename; | |
| 57 | + | float fadetime; | |
| 58 | + | float gain; | |
| 59 | + | }; | |
| 60 | + | std::deque<QueueEntry> m_queue; | |
| 61 | + | SoundSourcePtr m_currentSource; | |
| 62 | + | stdext::boolean<true> m_enabled; | |
| 63 | + | int m_id; | |
| 64 | + | float m_gain; | |
| 65 | + | }; | |
| 66 | + | ||
| 67 | + | #endif | |
| 68 | + | ||
| 69 | + | #endif |
| @@ -0,0 +1,72 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifdef FW_SOUND | |
| 24 | + | ||
| 25 | + | #include "soundfile.h" | |
| 26 | + | #include "oggsoundfile.h" | |
| 27 | + | #include <framework/core/resourcemanager.h> | |
| 28 | + | ||
| 29 | + | SoundFile::SoundFile(const FileStreamPtr& fileStream) | |
| 30 | + | { | |
| 31 | + | m_file = fileStream; | |
| 32 | + | } | |
| 33 | + | ||
| 34 | + | SoundFilePtr SoundFile::loadSoundFile(const std::string& filename) | |
| 35 | + | { | |
| 36 | + | stdext::timer t; | |
| 37 | + | FileStreamPtr file = g_resources.openFile(filename); | |
| 38 | + | if(!file) | |
| 39 | + | stdext::throw_exception(stdext::format("unable to open %s", filename)); | |
| 40 | + | ||
| 41 | + | char magic[4]; | |
| 42 | + | file->read(magic, 4); | |
| 43 | + | file->seek(0); | |
| 44 | + | ||
| 45 | + | SoundFilePtr soundFile; | |
| 46 | + | if(strncmp(magic, "OggS", 4) == 0) { | |
| 47 | + | OggSoundFilePtr oggSoundFile = OggSoundFilePtr(new OggSoundFile(file)); | |
| 48 | + | if(oggSoundFile->prepareOgg()) | |
| 49 | + | soundFile = oggSoundFile; | |
| 50 | + | } else | |
| 51 | + | stdext::throw_exception(stdext::format("unknown sound file format %s", filename)); | |
| 52 | + | ||
| 53 | + | return soundFile; | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | ALenum SoundFile::getSampleFormat() | |
| 57 | + | { | |
| 58 | + | if(m_channels == 2) { | |
| 59 | + | if(m_bps == 16) | |
| 60 | + | return AL_FORMAT_STEREO16; | |
| 61 | + | else if(m_bps == 8) | |
| 62 | + | return AL_FORMAT_STEREO8; | |
| 63 | + | } else if(m_channels == 1) { | |
| 64 | + | if(m_bps == 16) | |
| 65 | + | return AL_FORMAT_MONO16; | |
| 66 | + | else if(m_bps == 8) | |
| 67 | + | return AL_FORMAT_MONO8; | |
| 68 | + | } | |
| 69 | + | return AL_UNDETERMINED; | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | #endif |
| @@ -0,0 +1,60 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifdef FW_SOUND | |
| 24 | + | ||
| 25 | + | #ifndef SOUNDFILE_H | |
| 26 | + | #define SOUNDFILE_H | |
| 27 | + | ||
| 28 | + | #include "declarations.h" | |
| 29 | + | #include <framework/core/filestream.h> | |
| 30 | + | ||
| 31 | + | class SoundFile : public stdext::shared_object | |
| 32 | + | { | |
| 33 | + | public: | |
| 34 | + | SoundFile(const FileStreamPtr& fileStream); | |
| 35 | + | virtual ~SoundFile() { } | |
| 36 | + | static SoundFilePtr loadSoundFile(const std::string& filename); | |
| 37 | + | ||
| 38 | + | virtual int read(void *buffer, int bufferSize) { return -1; } | |
| 39 | + | virtual void reset() { } | |
| 40 | + | bool eof() { return m_file->eof(); } | |
| 41 | + | ||
| 42 | + | ALenum getSampleFormat(); | |
| 43 | + | ||
| 44 | + | int getChannels() { return m_channels; } | |
| 45 | + | int getRate() { return m_rate; } | |
| 46 | + | int getBps() { return m_bps; } | |
| 47 | + | int getSize() { return m_size; } | |
| 48 | + | std::string getName() { return m_file ? m_file->name() : std::string(); } | |
| 49 | + | ||
| 50 | + | protected: | |
| 51 | + | FileStreamPtr m_file; | |
| 52 | + | int m_channels; | |
| 53 | + | int m_rate; | |
| 54 | + | int m_bps; | |
| 55 | + | int m_size; | |
| 56 | + | }; | |
| 57 | + | ||
| 58 | + | #endif | |
| 59 | + | ||
| 60 | + | #endif |
| @@ -0,0 +1,303 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifdef FW_SOUND | |
| 24 | + | ||
| 25 | + | #include "soundmanager.h" | |
| 26 | + | #include "soundsource.h" | |
| 27 | + | #include "soundbuffer.h" | |
| 28 | + | #include "soundfile.h" | |
| 29 | + | #include "streamsoundsource.h" | |
| 30 | + | #include "combinedsoundsource.h" | |
| 31 | + | ||
| 32 | + | #include <framework/core/clock.h> | |
| 33 | + | #include <framework/core/eventdispatcher.h> | |
| 34 | + | #include <framework/core/resourcemanager.h> | |
| 35 | + | #include <framework/core/asyncdispatcher.h> | |
| 36 | + | #include <thread> | |
| 37 | + | #include <framework/util/stats.h> | |
| 38 | + | ||
| 39 | + | SoundManager g_sounds; | |
| 40 | + | ||
| 41 | + | void SoundManager::init() | |
| 42 | + | { | |
| 43 | + | m_device = alcOpenDevice(NULL); | |
| 44 | + | if(!m_device) { | |
| 45 | + | g_logger.error("unable to open audio device"); | |
| 46 | + | return; | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | m_context = alcCreateContext(m_device, NULL); | |
| 50 | + | if(!m_context) { | |
| 51 | + | g_logger.error(stdext::format("unable to create audio context: %s", alcGetString(m_device, alcGetError(m_device)))); | |
| 52 | + | return; | |
| 53 | + | } | |
| 54 | + | ||
| 55 | + | if(alcMakeContextCurrent(m_context) != ALC_TRUE) { | |
| 56 | + | g_logger.error(stdext::format("unable to make context current: %s", alcGetString(m_device, alcGetError(m_device)))); | |
| 57 | + | return; | |
| 58 | + | } | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | void SoundManager::terminate() | |
| 62 | + | { | |
| 63 | + | ensureContext(); | |
| 64 | + | ||
| 65 | + | for(auto it = m_streamFiles.begin(); it != m_streamFiles.end();++it) { | |
| 66 | + | auto& future = it->second; | |
| 67 | + | future.wait(); | |
| 68 | + | } | |
| 69 | + | m_streamFiles.clear(); | |
| 70 | + | ||
| 71 | + | m_sources.clear(); | |
| 72 | + | m_buffers.clear(); | |
| 73 | + | m_channels.clear(); | |
| 74 | + | ||
| 75 | + | m_audioEnabled = false; | |
| 76 | + | ||
| 77 | + | alcMakeContextCurrent(nullptr); | |
| 78 | + | ||
| 79 | + | if(m_context) { | |
| 80 | + | alcDestroyContext(m_context); | |
| 81 | + | m_context = nullptr; | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | if(m_device) { | |
| 85 | + | alcCloseDevice(m_device); | |
| 86 | + | m_device = nullptr; | |
| 87 | + | } | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | void SoundManager::poll() | |
| 91 | + | { | |
| 92 | + | AutoStat s(STATS_MAIN, "PollSounds"); | |
| 93 | + | ||
| 94 | + | static ticks_t lastUpdate = 0; | |
| 95 | + | ticks_t now = g_clock.millis(); | |
| 96 | + | ||
| 97 | + | if(now - lastUpdate < POLL_DELAY) | |
| 98 | + | return; | |
| 99 | + | ||
| 100 | + | lastUpdate = now; | |
| 101 | + | ||
| 102 | + | ensureContext(); | |
| 103 | + | ||
| 104 | + | for(auto it = m_streamFiles.begin(); it != m_streamFiles.end();) { | |
| 105 | + | StreamSoundSourcePtr source = it->first; | |
| 106 | + | auto& future = it->second; | |
| 107 | + | ||
| 108 | + | if(future.valid()) { | |
| 109 | + | SoundFilePtr sound = future.get(); | |
| 110 | + | if(sound) | |
| 111 | + | source->setSoundFile(sound); | |
| 112 | + | else | |
| 113 | + | source->stop(); | |
| 114 | + | it = m_streamFiles.erase(it); | |
| 115 | + | } else { | |
| 116 | + | ++it; | |
| 117 | + | } | |
| 118 | + | } | |
| 119 | + | ||
| 120 | + | for(auto it = m_sources.begin(); it != m_sources.end();) { | |
| 121 | + | SoundSourcePtr source = *it; | |
| 122 | + | ||
| 123 | + | source->update(); | |
| 124 | + | ||
| 125 | + | if(!source->isPlaying()) | |
| 126 | + | it = m_sources.erase(it); | |
| 127 | + | else | |
| 128 | + | ++it; | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | for(auto it : m_channels) { | |
| 132 | + | it.second->update(); | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | if(m_context) { | |
| 136 | + | alcProcessContext(m_context); | |
| 137 | + | } | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | void SoundManager::setAudioEnabled(bool enable) | |
| 141 | + | { | |
| 142 | + | if(m_audioEnabled == enable) | |
| 143 | + | return; | |
| 144 | + | ||
| 145 | + | m_audioEnabled = enable; | |
| 146 | + | if(!enable) { | |
| 147 | + | ensureContext(); | |
| 148 | + | for(const SoundSourcePtr& source : m_sources) { | |
| 149 | + | source->stop(); | |
| 150 | + | } | |
| 151 | + | } | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | void SoundManager::preload(std::string filename) | |
| 155 | + | { | |
| 156 | + | filename = resolveSoundFile(filename); | |
| 157 | + | ||
| 158 | + | auto it = m_buffers.find(filename); | |
| 159 | + | if(it != m_buffers.end()) | |
| 160 | + | return; | |
| 161 | + | ||
| 162 | + | ensureContext(); | |
| 163 | + | SoundFilePtr soundFile = SoundFile::loadSoundFile(filename); | |
| 164 | + | ||
| 165 | + | // only keep small files | |
| 166 | + | if(!soundFile || soundFile->getSize() > MAX_CACHE_SIZE) | |
| 167 | + | return; | |
| 168 | + | ||
| 169 | + | SoundBufferPtr buffer = SoundBufferPtr(new SoundBuffer); | |
| 170 | + | if(buffer->fillBuffer(soundFile)) | |
| 171 | + | m_buffers[filename] = buffer; | |
| 172 | + | } | |
| 173 | + | ||
| 174 | + | SoundSourcePtr SoundManager::play(std::string filename, float fadetime, float gain) | |
| 175 | + | { | |
| 176 | + | if(!m_audioEnabled) | |
| 177 | + | return nullptr; | |
| 178 | + | ||
| 179 | + | ensureContext(); | |
| 180 | + | ||
| 181 | + | filename = resolveSoundFile(filename); | |
| 182 | + | SoundSourcePtr soundSource = createSoundSource(filename); | |
| 183 | + | if(!soundSource) { | |
| 184 | + | g_logger.error(stdext::format("unable to play '%s'", filename)); | |
| 185 | + | return nullptr; | |
| 186 | + | } | |
| 187 | + | ||
| 188 | + | soundSource->setName(filename); | |
| 189 | + | soundSource->setRelative(true); | |
| 190 | + | soundSource->setGain(gain); | |
| 191 | + | ||
| 192 | + | if(fadetime > 0) | |
| 193 | + | soundSource->setFading(StreamSoundSource::FadingOn, fadetime); | |
| 194 | + | ||
| 195 | + | soundSource->play(); | |
| 196 | + | ||
| 197 | + | m_sources.push_back(soundSource); | |
| 198 | + | ||
| 199 | + | return soundSource; | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | SoundChannelPtr SoundManager::getChannel(int channel) | |
| 203 | + | { | |
| 204 | + | ensureContext(); | |
| 205 | + | if(!m_channels[channel]) | |
| 206 | + | m_channels[channel] = SoundChannelPtr(new SoundChannel(channel)); | |
| 207 | + | return m_channels[channel]; | |
| 208 | + | } | |
| 209 | + | ||
| 210 | + | void SoundManager::stopAll() | |
| 211 | + | { | |
| 212 | + | ensureContext(); | |
| 213 | + | for(const SoundSourcePtr& source : m_sources) { | |
| 214 | + | source->stop(); | |
| 215 | + | } | |
| 216 | + | ||
| 217 | + | for(auto it : m_channels) { | |
| 218 | + | it.second->stop(); | |
| 219 | + | } | |
| 220 | + | } | |
| 221 | + | ||
| 222 | + | SoundSourcePtr SoundManager::createSoundSource(const std::string& filename) | |
| 223 | + | { | |
| 224 | + | SoundSourcePtr source; | |
| 225 | + | ||
| 226 | + | try { | |
| 227 | + | auto it = m_buffers.find(filename); | |
| 228 | + | if(it != m_buffers.end()) { | |
| 229 | + | source = SoundSourcePtr(new SoundSource); | |
| 230 | + | source->setBuffer(it->second); | |
| 231 | + | } else { | |
| 232 | + | #if defined __linux && !defined OPENGL_ES | |
| 233 | + | // due to OpenAL implementation bug, stereo buffers are always downmixed to mono on linux systems | |
| 234 | + | // this is hack to work around the issue | |
| 235 | + | // solution taken from http://opensource.creative.com/pipermail/openal/2007-April/010355.html | |
| 236 | + | CombinedSoundSourcePtr combinedSource(new CombinedSoundSource); | |
| 237 | + | StreamSoundSourcePtr streamSource; | |
| 238 | + | ||
| 239 | + | streamSource = StreamSoundSourcePtr(new StreamSoundSource); | |
| 240 | + | streamSource->downMix(StreamSoundSource::DownMixLeft); | |
| 241 | + | streamSource->setRelative(true); | |
| 242 | + | streamSource->setPosition(Point(-128, 0)); | |
| 243 | + | combinedSource->addSource(streamSource); | |
| 244 | + | m_streamFiles[streamSource] = g_asyncDispatcher.schedule([=]() -> SoundFilePtr { | |
| 245 | + | stdext::timer a; | |
| 246 | + | try { | |
| 247 | + | return SoundFile::loadSoundFile(filename); | |
| 248 | + | } catch(std::exception& e) { | |
| 249 | + | g_logger.error(e.what()); | |
| 250 | + | return nullptr; | |
| 251 | + | } | |
| 252 | + | }); | |
| 253 | + | ||
| 254 | + | streamSource = StreamSoundSourcePtr(new StreamSoundSource); | |
| 255 | + | streamSource->downMix(StreamSoundSource::DownMixRight); | |
| 256 | + | streamSource->setRelative(true); | |
| 257 | + | streamSource->setPosition(Point(128,0)); | |
| 258 | + | combinedSource->addSource(streamSource); | |
| 259 | + | m_streamFiles[streamSource] = g_asyncDispatcher.schedule([=]() -> SoundFilePtr { | |
| 260 | + | try { | |
| 261 | + | return SoundFile::loadSoundFile(filename); | |
| 262 | + | } catch(std::exception& e) { | |
| 263 | + | g_logger.error(e.what()); | |
| 264 | + | return nullptr; | |
| 265 | + | } | |
| 266 | + | }); | |
| 267 | + | ||
| 268 | + | source = combinedSource; | |
| 269 | + | #else | |
| 270 | + | StreamSoundSourcePtr streamSource(new StreamSoundSource); | |
| 271 | + | m_streamFiles[streamSource] = g_asyncDispatcher.schedule([=]() -> SoundFilePtr { | |
| 272 | + | try { | |
| 273 | + | return SoundFile::loadSoundFile(filename); | |
| 274 | + | } catch(std::exception& e) { | |
| 275 | + | g_logger.error(e.what()); | |
| 276 | + | return nullptr; | |
| 277 | + | } | |
| 278 | + | }); | |
| 279 | + | source = streamSource; | |
| 280 | + | #endif | |
| 281 | + | } | |
| 282 | + | } catch(std::exception& e) { | |
| 283 | + | g_logger.error(stdext::format("failed to load sound source: '%s'", e.what())); | |
| 284 | + | return nullptr; | |
| 285 | + | } | |
| 286 | + | ||
| 287 | + | return source; | |
| 288 | + | } | |
| 289 | + | ||
| 290 | + | std::string SoundManager::resolveSoundFile(std::string file) | |
| 291 | + | { | |
| 292 | + | file = g_resources.guessFilePath(file, "ogg"); | |
| 293 | + | file = g_resources.resolvePath(file); | |
| 294 | + | return file; | |
| 295 | + | } | |
| 296 | + | ||
| 297 | + | void SoundManager::ensureContext() | |
| 298 | + | { | |
| 299 | + | if(m_context) | |
| 300 | + | alcMakeContextCurrent(m_context); | |
| 301 | + | } | |
| 302 | + | ||
| 303 | + | #endif |
| @@ -0,0 +1,73 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifdef FW_SOUND | |
| 24 | + | ||
| 25 | + | #ifndef SOUNDMANAGER_H | |
| 26 | + | #define SOUNDMANAGER_H | |
| 27 | + | ||
| 28 | + | #include "declarations.h" | |
| 29 | + | #include "soundchannel.h" | |
| 30 | + | ||
| 31 | + | //@bindsingleton g_sounds | |
| 32 | + | class SoundManager | |
| 33 | + | { | |
| 34 | + | enum { | |
| 35 | + | MAX_CACHE_SIZE = 100000, | |
| 36 | + | POLL_DELAY = 100 | |
| 37 | + | }; | |
| 38 | + | public: | |
| 39 | + | void init(); | |
| 40 | + | void terminate(); | |
| 41 | + | void poll(); | |
| 42 | + | ||
| 43 | + | void setAudioEnabled(bool enable); | |
| 44 | + | bool isAudioEnabled() { return m_device && m_context && m_audioEnabled ; } | |
| 45 | + | void enableAudio() { setAudioEnabled(true); } | |
| 46 | + | void disableAudio() { setAudioEnabled(true); } | |
| 47 | + | void stopAll(); | |
| 48 | + | ||
| 49 | + | void preload(std::string filename); | |
| 50 | + | SoundSourcePtr play(std::string filename, float fadetime = 0, float gain = 0); | |
| 51 | + | SoundChannelPtr getChannel(int channel); | |
| 52 | + | ||
| 53 | + | std::string resolveSoundFile(std::string file); | |
| 54 | + | void ensureContext(); | |
| 55 | + | ||
| 56 | + | private: | |
| 57 | + | SoundSourcePtr createSoundSource(const std::string& filename); | |
| 58 | + | ||
| 59 | + | ALCdevice *m_device; | |
| 60 | + | ALCcontext *m_context; | |
| 61 | + | ||
| 62 | + | std::map<StreamSoundSourcePtr, std::shared_future<SoundFilePtr>> m_streamFiles; | |
| 63 | + | std::unordered_map<std::string, SoundBufferPtr> m_buffers; | |
| 64 | + | std::vector<SoundSourcePtr> m_sources; | |
| 65 | + | stdext::boolean<true> m_audioEnabled; | |
| 66 | + | std::unordered_map<int, SoundChannelPtr> m_channels; | |
| 67 | + | }; | |
| 68 | + | ||
| 69 | + | extern SoundManager g_sounds; | |
| 70 | + | ||
| 71 | + | #endif | |
| 72 | + | ||
| 73 | + | #endif |
| @@ -0,0 +1,165 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifdef FW_SOUND | |
| 24 | + | ||
| 25 | + | #include "soundsource.h" | |
| 26 | + | #include "soundbuffer.h" | |
| 27 | + | ||
| 28 | + | #include <framework/core/clock.h> | |
| 29 | + | ||
| 30 | + | SoundSource::SoundSource() | |
| 31 | + | { | |
| 32 | + | m_sourceId = 0; | |
| 33 | + | m_channel = 0; | |
| 34 | + | m_fadeState = NoFading; | |
| 35 | + | m_fadeTime = 0; | |
| 36 | + | m_fadeStartTime = 0; | |
| 37 | + | m_fadeGain = 0; | |
| 38 | + | m_gain = 1.0f; | |
| 39 | + | ||
| 40 | + | alGenSources(1, &m_sourceId); | |
| 41 | + | VALIDATE(alGetError() == AL_NO_ERROR); | |
| 42 | + | setReferenceDistance(128); | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | SoundSource::~SoundSource() | |
| 46 | + | { | |
| 47 | + | if(m_sourceId != 0) { | |
| 48 | + | stop(); | |
| 49 | + | alDeleteSources(1, &m_sourceId); | |
| 50 | + | VALIDATE(alGetError() == AL_NO_ERROR); | |
| 51 | + | } | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | void SoundSource::play() | |
| 55 | + | { | |
| 56 | + | alSourcePlay(m_sourceId); | |
| 57 | + | VALIDATE(alGetError() == AL_NO_ERROR); | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | void SoundSource::stop() | |
| 61 | + | { | |
| 62 | + | alSourceStop(m_sourceId); | |
| 63 | + | VALIDATE(alGetError() == AL_NO_ERROR); | |
| 64 | + | if(m_buffer) { | |
| 65 | + | alSourcei(m_sourceId, AL_BUFFER, AL_NONE); | |
| 66 | + | VALIDATE(alGetError() == AL_NO_ERROR); | |
| 67 | + | m_buffer = nullptr; | |
| 68 | + | } | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | bool SoundSource::isBuffering() | |
| 72 | + | { | |
| 73 | + | int state = AL_PLAYING; | |
| 74 | + | alGetSourcei(m_sourceId, AL_SOURCE_STATE, &state); | |
| 75 | + | return state != AL_STOPPED; | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | void SoundSource::setBuffer(const SoundBufferPtr& buffer) | |
| 79 | + | { | |
| 80 | + | alSourcei(m_sourceId, AL_BUFFER, buffer->getBufferId()); | |
| 81 | + | VALIDATE(alGetError() == AL_NO_ERROR); | |
| 82 | + | m_buffer = buffer; | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | void SoundSource::setLooping(bool looping) | |
| 86 | + | { | |
| 87 | + | alSourcei(m_sourceId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE); | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | void SoundSource::setRelative(bool relative) | |
| 91 | + | { | |
| 92 | + | alSourcei(m_sourceId, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE); | |
| 93 | + | } | |
| 94 | + | ||
| 95 | + | void SoundSource::setReferenceDistance(float distance) | |
| 96 | + | { | |
| 97 | + | alSourcef(m_sourceId, AL_REFERENCE_DISTANCE, distance); | |
| 98 | + | } | |
| 99 | + | ||
| 100 | + | void SoundSource::setGain(float gain) | |
| 101 | + | { | |
| 102 | + | alSourcef(m_sourceId, AL_GAIN, gain); | |
| 103 | + | m_gain = gain; | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | void SoundSource::setPitch(float pitch) | |
| 107 | + | { | |
| 108 | + | alSourcef(m_sourceId, AL_PITCH, pitch); | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | void SoundSource::setPosition(const Point& pos) | |
| 112 | + | { | |
| 113 | + | alSource3f(m_sourceId, AL_POSITION, pos.x, pos.y, 0); | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | void SoundSource::setVelocity(const Point& velocity) | |
| 117 | + | { | |
| 118 | + | alSource3f(m_sourceId, AL_VELOCITY, velocity.x, velocity.y, 0); | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | void SoundSource::setFading(FadeState state, float fadeTime) | |
| 122 | + | { | |
| 123 | + | float now = stdext::millis() / 1000.0f; | |
| 124 | + | if(m_fadeState != NoFading) { | |
| 125 | + | float elapsed = now - m_fadeStartTime; | |
| 126 | + | float add; | |
| 127 | + | if(m_fadeState == FadingOn) | |
| 128 | + | add = -(1-(elapsed / m_fadeTime))*fadeTime; | |
| 129 | + | else | |
| 130 | + | add = -(elapsed / m_fadeTime)*fadeTime; | |
| 131 | + | m_fadeStartTime = now + add; | |
| 132 | + | } else | |
| 133 | + | m_fadeStartTime = now; | |
| 134 | + | ||
| 135 | + | m_fadeState = state; | |
| 136 | + | m_fadeTime = fadeTime; | |
| 137 | + | m_fadeGain = m_gain; | |
| 138 | + | ||
| 139 | + | if(m_fadeState == FadingOn) | |
| 140 | + | setGain(0.0); | |
| 141 | + | } | |
| 142 | + | ||
| 143 | + | void SoundSource::update() | |
| 144 | + | { | |
| 145 | + | float now = stdext::millis() / 1000.0f; | |
| 146 | + | if(m_fadeState == FadingOn) { | |
| 147 | + | float elapsed = now - m_fadeStartTime; | |
| 148 | + | if(elapsed >= m_fadeTime) { | |
| 149 | + | m_fadeState = NoFading; | |
| 150 | + | } else { | |
| 151 | + | setGain((elapsed / m_fadeTime) * m_fadeGain); | |
| 152 | + | } | |
| 153 | + | } else if(m_fadeState == FadingOff) { | |
| 154 | + | float elapsed = now - m_fadeStartTime; | |
| 155 | + | if(elapsed >= m_fadeTime) { | |
| 156 | + | setGain(m_fadeGain); | |
| 157 | + | stop(); | |
| 158 | + | m_fadeState = NoFading; | |
| 159 | + | } else { | |
| 160 | + | setGain(((m_fadeTime - elapsed) / m_fadeTime) * m_fadeGain); | |
| 161 | + | } | |
| 162 | + | } | |
| 163 | + | } | |
| 164 | + | ||
| 165 | + | #endif |
| @@ -0,0 +1,84 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifdef FW_SOUND | |
| 24 | + | ||
| 25 | + | #ifndef SOUNDSOURCE_H | |
| 26 | + | #define SOUNDSOURCE_H | |
| 27 | + | ||
| 28 | + | #include "declarations.h" | |
| 29 | + | #include "soundbuffer.h" | |
| 30 | + | #include <framework/luaengine/luaobject.h> | |
| 31 | + | ||
| 32 | + | class SoundSource : public LuaObject | |
| 33 | + | { | |
| 34 | + | protected: | |
| 35 | + | SoundSource(uint sourceId) : m_sourceId(sourceId) { } | |
| 36 | + | ||
| 37 | + | public: | |
| 38 | + | enum FadeState { NoFading, FadingOn, FadingOff }; | |
| 39 | + | ||
| 40 | + | SoundSource(); | |
| 41 | + | virtual ~SoundSource(); | |
| 42 | + | ||
| 43 | + | virtual void play(); | |
| 44 | + | virtual void stop(); | |
| 45 | + | ||
| 46 | + | virtual bool isBuffering(); | |
| 47 | + | virtual bool isPlaying() { return isBuffering(); } | |
| 48 | + | ||
| 49 | + | void setName(const std::string& name) { m_name = name; } | |
| 50 | + | virtual void setLooping(bool looping); | |
| 51 | + | virtual void setRelative(bool relative); | |
| 52 | + | virtual void setReferenceDistance(float distance); | |
| 53 | + | virtual void setGain(float gain); | |
| 54 | + | virtual void setPitch(float pitch); | |
| 55 | + | virtual void setPosition(const Point& pos); | |
| 56 | + | virtual void setVelocity(const Point& velocity); | |
| 57 | + | virtual void setFading(FadeState state, float fadetime); | |
| 58 | + | ||
| 59 | + | std::string getName() { return m_name; } | |
| 60 | + | uchar getChannel() { return m_channel; } | |
| 61 | + | float getGain() { return m_gain; } | |
| 62 | + | ||
| 63 | + | protected: | |
| 64 | + | void setBuffer(const SoundBufferPtr& buffer); | |
| 65 | + | void setChannel(uchar channel) { m_channel = channel; } | |
| 66 | + | ||
| 67 | + | virtual void update(); | |
| 68 | + | friend class SoundManager; | |
| 69 | + | friend class CombinedSoundSource; | |
| 70 | + | ||
| 71 | + | uint m_sourceId; | |
| 72 | + | uchar m_channel; | |
| 73 | + | std::string m_name; | |
| 74 | + | SoundBufferPtr m_buffer; | |
| 75 | + | FadeState m_fadeState; | |
| 76 | + | float m_fadeStartTime; | |
| 77 | + | float m_fadeTime; | |
| 78 | + | float m_fadeGain; | |
| 79 | + | float m_gain; | |
| 80 | + | }; | |
| 81 | + | ||
| 82 | + | #endif | |
| 83 | + | ||
| 84 | + | #endif |
| @@ -0,0 +1,193 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifdef FW_SOUND | |
| 24 | + | ||
| 25 | + | #include "streamsoundsource.h" | |
| 26 | + | #include "soundbuffer.h" | |
| 27 | + | #include "soundfile.h" | |
| 28 | + | ||
| 29 | + | #include <framework/util/databuffer.h> | |
| 30 | + | #include <boost/concept_check.hpp> | |
| 31 | + | ||
| 32 | + | StreamSoundSource::StreamSoundSource() | |
| 33 | + | { | |
| 34 | + | for(auto& buffer : m_buffers) | |
| 35 | + | buffer = SoundBufferPtr(new SoundBuffer); | |
| 36 | + | m_downMix = NoDownMix; | |
| 37 | + | } | |
| 38 | + | ||
| 39 | + | StreamSoundSource::~StreamSoundSource() | |
| 40 | + | { | |
| 41 | + | stop(); | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | void StreamSoundSource::setSoundFile(const SoundFilePtr& soundFile) | |
| 45 | + | { | |
| 46 | + | m_soundFile = soundFile; | |
| 47 | + | if(m_waitingFile) { | |
| 48 | + | m_waitingFile = false; | |
| 49 | + | play(); | |
| 50 | + | } | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | void StreamSoundSource::play() | |
| 54 | + | { | |
| 55 | + | m_playing = true; | |
| 56 | + | ||
| 57 | + | if(!m_soundFile) { | |
| 58 | + | m_waitingFile = true; | |
| 59 | + | return; | |
| 60 | + | } | |
| 61 | + | ||
| 62 | + | if(m_eof) { | |
| 63 | + | m_soundFile->reset(); | |
| 64 | + | m_eof = false; | |
| 65 | + | } | |
| 66 | + | ||
| 67 | + | queueBuffers(); | |
| 68 | + | ||
| 69 | + | SoundSource::play(); | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | void StreamSoundSource::stop() | |
| 73 | + | { | |
| 74 | + | m_playing = false; | |
| 75 | + | ||
| 76 | + | if(m_waitingFile) | |
| 77 | + | return; | |
| 78 | + | ||
| 79 | + | SoundSource::stop(); | |
| 80 | + | unqueueBuffers(); | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | void StreamSoundSource::queueBuffers() | |
| 84 | + | { | |
| 85 | + | int queued; | |
| 86 | + | alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queued); | |
| 87 | + | for(int i = 0; i < STREAM_FRAGMENTS - queued; ++i) { | |
| 88 | + | if(!fillBufferAndQueue(m_buffers[i]->getBufferId())) | |
| 89 | + | break; | |
| 90 | + | } | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | void StreamSoundSource::unqueueBuffers() | |
| 94 | + | { | |
| 95 | + | int queued; | |
| 96 | + | alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queued); | |
| 97 | + | for(int i = 0; i < queued; ++i) { | |
| 98 | + | uint buffer; | |
| 99 | + | alSourceUnqueueBuffers(m_sourceId, 1, &buffer); | |
| 100 | + | } | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | void StreamSoundSource::update() | |
| 104 | + | { | |
| 105 | + | if(m_waitingFile) | |
| 106 | + | return; | |
| 107 | + | ||
| 108 | + | SoundSource::update(); | |
| 109 | + | ||
| 110 | + | int processed = 0; | |
| 111 | + | alGetSourcei(m_sourceId, AL_BUFFERS_PROCESSED, &processed); | |
| 112 | + | for(int i = 0; i < processed; ++i) { | |
| 113 | + | uint buffer; | |
| 114 | + | alSourceUnqueueBuffers(m_sourceId, 1, &buffer); | |
| 115 | + | //SoundManager::check_al_error("Couldn't unqueue audio buffer: "); | |
| 116 | + | ||
| 117 | + | if(!fillBufferAndQueue(buffer)) | |
| 118 | + | break; | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | if(!isBuffering() && m_playing) { | |
| 122 | + | if(!m_looping && m_eof) { | |
| 123 | + | stop(); | |
| 124 | + | } else if(processed == 0) { | |
| 125 | + | g_logger.traceError("audio buffer underrun"); | |
| 126 | + | play(); | |
| 127 | + | } else if(m_looping) { | |
| 128 | + | play(); | |
| 129 | + | } | |
| 130 | + | } | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | bool StreamSoundSource::fillBufferAndQueue(uint buffer) | |
| 134 | + | { | |
| 135 | + | if(m_waitingFile) | |
| 136 | + | return false; | |
| 137 | + | ||
| 138 | + | // fill buffer | |
| 139 | + | static DataBuffer<char> bufferData(2*STREAM_FRAGMENT_SIZE); | |
| 140 | + | ALenum format = m_soundFile->getSampleFormat(); | |
| 141 | + | ||
| 142 | + | int maxRead = STREAM_FRAGMENT_SIZE; | |
| 143 | + | if(m_downMix != NoDownMix) | |
| 144 | + | maxRead *= 2; | |
| 145 | + | ||
| 146 | + | int bytesRead = 0; | |
| 147 | + | do { | |
| 148 | + | bytesRead += m_soundFile->read(&bufferData[bytesRead], maxRead - bytesRead); | |
| 149 | + | ||
| 150 | + | // end of sound file | |
| 151 | + | if(bytesRead < maxRead) { | |
| 152 | + | if(m_looping) | |
| 153 | + | m_soundFile->reset(); | |
| 154 | + | else { | |
| 155 | + | m_eof = true; | |
| 156 | + | break; | |
| 157 | + | } | |
| 158 | + | } | |
| 159 | + | } while(bytesRead < maxRead); | |
| 160 | + | ||
| 161 | + | if(bytesRead > 0) { | |
| 162 | + | if(m_downMix != NoDownMix) { | |
| 163 | + | if(format == AL_FORMAT_STEREO16) { | |
| 164 | + | VALIDATE(bytesRead % 2 == 0); | |
| 165 | + | bytesRead /= 2; | |
| 166 | + | uint16_t *data = (uint16_t*)bufferData.data(); | |
| 167 | + | for(int i=0;i<bytesRead/2;i++) | |
| 168 | + | data[i] = data[2*i + (m_downMix == DownMixLeft ? 0 : 1)]; | |
| 169 | + | format = AL_FORMAT_MONO16; | |
| 170 | + | } | |
| 171 | + | } | |
| 172 | + | ||
| 173 | + | alBufferData(buffer, format, &bufferData[0], bytesRead, m_soundFile->getRate()); | |
| 174 | + | ALenum err = alGetError(); | |
| 175 | + | if(err != AL_NO_ERROR) | |
| 176 | + | g_logger.error(stdext::format("unable to refill audio buffer for '%s': %s", m_soundFile->getName(), alGetString(err))); | |
| 177 | + | ||
| 178 | + | alSourceQueueBuffers(m_sourceId, 1, &buffer); | |
| 179 | + | err = alGetError(); | |
| 180 | + | if(err != AL_NO_ERROR) | |
| 181 | + | g_logger.error(stdext::format("unable to queue audio buffer for '%s': %s", m_soundFile->getName(), alGetString(err))); | |
| 182 | + | } | |
| 183 | + | ||
| 184 | + | // return false if there aren't more buffers to fill | |
| 185 | + | return (bytesRead >= STREAM_FRAGMENT_SIZE && !m_eof); | |
| 186 | + | } | |
| 187 | + | ||
| 188 | + | void StreamSoundSource::downMix(StreamSoundSource::DownMix downMix) | |
| 189 | + | { | |
| 190 | + | m_downMix = downMix; | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | #endif |
| @@ -0,0 +1,71 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifdef FW_SOUND | |
| 24 | + | ||
| 25 | + | #ifndef STREAMSOUNDSOURCE_H | |
| 26 | + | #define STREAMSOUNDSOURCE_H | |
| 27 | + | ||
| 28 | + | #include "soundsource.h" | |
| 29 | + | ||
| 30 | + | class StreamSoundSource : public SoundSource | |
| 31 | + | { | |
| 32 | + | enum { | |
| 33 | + | STREAM_BUFFER_SIZE = 1024 * 400, | |
| 34 | + | STREAM_FRAGMENTS = 4, | |
| 35 | + | STREAM_FRAGMENT_SIZE = STREAM_BUFFER_SIZE / STREAM_FRAGMENTS | |
| 36 | + | }; | |
| 37 | + | ||
| 38 | + | public: | |
| 39 | + | enum DownMix { NoDownMix, DownMixLeft, DownMixRight }; | |
| 40 | + | ||
| 41 | + | StreamSoundSource(); | |
| 42 | + | virtual ~StreamSoundSource(); | |
| 43 | + | ||
| 44 | + | void play(); | |
| 45 | + | void stop(); | |
| 46 | + | ||
| 47 | + | bool isPlaying() { return m_playing; } | |
| 48 | + | ||
| 49 | + | void setSoundFile(const SoundFilePtr& soundFile); | |
| 50 | + | ||
| 51 | + | void downMix(DownMix downMix); | |
| 52 | + | ||
| 53 | + | void update(); | |
| 54 | + | ||
| 55 | + | private: | |
| 56 | + | void queueBuffers(); | |
| 57 | + | void unqueueBuffers(); | |
| 58 | + | bool fillBufferAndQueue(uint buffer); | |
| 59 | + | ||
| 60 | + | SoundFilePtr m_soundFile; | |
| 61 | + | std::array<SoundBufferPtr,STREAM_FRAGMENTS> m_buffers; | |
| 62 | + | DownMix m_downMix; | |
| 63 | + | stdext::boolean<false> m_looping; | |
| 64 | + | stdext::boolean<false> m_playing; | |
| 65 | + | stdext::boolean<false> m_eof; | |
| 66 | + | stdext::boolean<false> m_waitingFile; | |
| 67 | + | }; | |
| 68 | + | ||
| 69 | + | #endif | |
| 70 | + | ||
| 71 | + | #endif |
| @@ -0,0 +1,76 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_ANY_H | |
| 24 | + | #define STDEXT_ANY_H | |
| 25 | + | ||
| 26 | + | #include <algorithm> | |
| 27 | + | #include <typeinfo> | |
| 28 | + | ||
| 29 | + | namespace stdext { | |
| 30 | + | ||
| 31 | + | class any { | |
| 32 | + | public: | |
| 33 | + | struct placeholder { | |
| 34 | + | virtual ~placeholder() { } | |
| 35 | + | virtual const std::type_info& type() const = 0; | |
| 36 | + | virtual placeholder* clone() const = 0; | |
| 37 | + | }; | |
| 38 | + | ||
| 39 | + | template<typename T> | |
| 40 | + | struct holder : public placeholder { | |
| 41 | + | holder(const T& value) : held(value) { } | |
| 42 | + | const std::type_info& type() const { return typeid(T); } | |
| 43 | + | placeholder* clone() const { return new holder(held); } | |
| 44 | + | T held; | |
| 45 | + | private: | |
| 46 | + | holder& operator=(const holder &); | |
| 47 | + | }; | |
| 48 | + | ||
| 49 | + | placeholder* content; | |
| 50 | + | ||
| 51 | + | any() : content(nullptr) { } | |
| 52 | + | any(const any& other) : content(other.content ? other.content->clone() : nullptr) { } | |
| 53 | + | template<typename T> any(const T& value) : content(new holder<T>(value)) { } | |
| 54 | + | ~any() { if(content) delete content; } | |
| 55 | + | ||
| 56 | + | any& swap(any& rhs) { std::swap(content, rhs.content); return *this; } | |
| 57 | + | ||
| 58 | + | template<typename T> any& operator=(const T& rhs) { any(rhs).swap(*this); return *this; } | |
| 59 | + | any& operator=(any rhs) { rhs.swap(*this); return *this; } | |
| 60 | + | ||
| 61 | + | bool empty() const { return !content; } | |
| 62 | + | template<typename T> const T& cast() const; | |
| 63 | + | const std::type_info & type() const { return content ? content->type() : typeid(void); } | |
| 64 | + | }; | |
| 65 | + | ||
| 66 | + | template<typename T> | |
| 67 | + | const T& any_cast(const any& operand) { | |
| 68 | + | VALIDATE(operand.type() == typeid(T)); | |
| 69 | + | return static_cast<any::holder<T>*>(operand.content)->held; | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | template<typename T> const T& any::cast() const { return any_cast<T>(*this); } | |
| 73 | + | ||
| 74 | + | } | |
| 75 | + | ||
| 76 | + | #endif |
| @@ -0,0 +1,40 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef BOOLEAN_H | |
| 24 | + | #define BOOLEAN_H | |
| 25 | + | ||
| 26 | + | namespace stdext { | |
| 27 | + | ||
| 28 | + | template<bool def> | |
| 29 | + | struct boolean { | |
| 30 | + | boolean() : v(def) { } | |
| 31 | + | operator bool &() { return v; } | |
| 32 | + | operator bool const &() const { return v; } | |
| 33 | + | bool& operator=(const bool& o) { v = o; return v; } | |
| 34 | + | private: | |
| 35 | + | bool v; | |
| 36 | + | }; | |
| 37 | + | ||
| 38 | + | } | |
| 39 | + | ||
| 40 | + | #endif |
| @@ -0,0 +1,177 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_CAST_H | |
| 24 | + | #define STDEXT_CAST_H | |
| 25 | + | ||
| 26 | + | #include "exception.h" | |
| 27 | + | #include "demangle.h" | |
| 28 | + | ||
| 29 | + | #include <sstream> | |
| 30 | + | #include <iostream> | |
| 31 | + | #include <cstdlib> | |
| 32 | + | ||
| 33 | + | namespace stdext { | |
| 34 | + | ||
| 35 | + | // cast a type to another type | |
| 36 | + | template<typename T, typename R> | |
| 37 | + | bool cast(const T& in, R& out) { | |
| 38 | + | std::stringstream ss; | |
| 39 | + | ss << in; | |
| 40 | + | ss >> out; | |
| 41 | + | return !!ss && ss.eof(); | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | // cast a type to string | |
| 45 | + | template<typename T> | |
| 46 | + | bool cast(const T& in, std::string& out) { | |
| 47 | + | std::stringstream ss; | |
| 48 | + | ss << in; | |
| 49 | + | out = ss.str(); | |
| 50 | + | return true; | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // cast string to string | |
| 54 | + | template<> | |
| 55 | + | inline bool cast(const std::string& in, std::string& out) { | |
| 56 | + | out = in; | |
| 57 | + | return true; | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | // special cast from string to boolean | |
| 61 | + | template<> | |
| 62 | + | inline bool cast(const std::string& in, bool& b) { | |
| 63 | + | if(in == "true") | |
| 64 | + | b = true; | |
| 65 | + | else if(in == "false") | |
| 66 | + | b = false; | |
| 67 | + | else | |
| 68 | + | return false; | |
| 69 | + | return true; | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // special cast from string to char | |
| 73 | + | template<> | |
| 74 | + | inline bool cast(const std::string& in, char& c) { | |
| 75 | + | if(in.length() != 1) | |
| 76 | + | return false; | |
| 77 | + | c = in[0]; | |
| 78 | + | return true; | |
| 79 | + | } | |
| 80 | + | ||
| 81 | + | // special cast from string to long | |
| 82 | + | template<> | |
| 83 | + | inline bool cast(const std::string& in, long& l) { | |
| 84 | + | if(in.find_first_not_of("-0123456789") != std::string::npos) | |
| 85 | + | return false; | |
| 86 | + | std::size_t t = in.find_last_of('-'); | |
| 87 | + | if(t != std::string::npos && t != 0) | |
| 88 | + | return false; | |
| 89 | + | l = atol(in.c_str()); | |
| 90 | + | return true; | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // special cast from string to int | |
| 94 | + | template<> | |
| 95 | + | inline bool cast(const std::string& in, int& i) { | |
| 96 | + | long l; | |
| 97 | + | if(cast(in, l)) { | |
| 98 | + | i=l; | |
| 99 | + | return true; | |
| 100 | + | } | |
| 101 | + | return false; | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // special cast from string to double | |
| 105 | + | template<> | |
| 106 | + | inline bool cast(const std::string& in, double& d) { | |
| 107 | + | if(in.find_first_not_of("-0123456789.") != std::string::npos) | |
| 108 | + | return false; | |
| 109 | + | std::size_t t = in.find_last_of('-'); | |
| 110 | + | if(t != std::string::npos && t != 0) | |
| 111 | + | return false; | |
| 112 | + | t = in.find_first_of('.'); | |
| 113 | + | if(t != std::string::npos && (t == 0 || t == in.length()-1 || in.find_first_of('.', t+1) != std::string::npos)) | |
| 114 | + | return false; | |
| 115 | + | d = atof(in.c_str()); | |
| 116 | + | return true; | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // special cast from string to float | |
| 120 | + | template<> | |
| 121 | + | inline bool cast(const std::string& in, float& f) { | |
| 122 | + | double d; | |
| 123 | + | if(cast(in, d)) { | |
| 124 | + | f=(float)d; | |
| 125 | + | return true; | |
| 126 | + | } | |
| 127 | + | return false; | |
| 128 | + | } | |
| 129 | + | ||
| 130 | + | // special cast from boolean to string | |
| 131 | + | template<> | |
| 132 | + | inline bool cast(const bool& in, std::string& out) { | |
| 133 | + | out = (in ? "true" : "false"); | |
| 134 | + | return true; | |
| 135 | + | } | |
| 136 | + | ||
| 137 | + | // used by safe_cast | |
| 138 | + | class cast_exception : public exception { | |
| 139 | + | public: | |
| 140 | + | virtual ~cast_exception() throw() { } | |
| 141 | + | template<class T, class R> | |
| 142 | + | void update_what() { | |
| 143 | + | std::stringstream ss; | |
| 144 | + | ss << "failed to cast value of type '" << demangle_type<T>() << "' to type '" << demangle_type<R>() << "'"; | |
| 145 | + | m_what = ss.str(); | |
| 146 | + | } | |
| 147 | + | virtual const char* what() const throw() { return m_what.c_str(); } | |
| 148 | + | private: | |
| 149 | + | std::string m_what; | |
| 150 | + | }; | |
| 151 | + | ||
| 152 | + | // cast a type to another type, any error throws a cast_exception | |
| 153 | + | template<typename R, typename T> | |
| 154 | + | R safe_cast(const T& t) { | |
| 155 | + | R r; | |
| 156 | + | if(!cast(t, r)) { | |
| 157 | + | cast_exception e; | |
| 158 | + | e.update_what<T,R>(); | |
| 159 | + | throw e; | |
| 160 | + | } | |
| 161 | + | return r; | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | // cast a type to another type, cast errors are ignored | |
| 165 | + | template<typename R, typename T> | |
| 166 | + | R unsafe_cast(const T& t, R def = R()) { | |
| 167 | + | try { | |
| 168 | + | return safe_cast<R,T>(t); | |
| 169 | + | } catch(cast_exception& e) { | |
| 170 | + | std::cerr << "CAST ERROR: " << e.what() << std::endl; | |
| 171 | + | return def; | |
| 172 | + | } | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | } | |
| 176 | + | ||
| 177 | + | #endif |
| @@ -0,0 +1,79 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_COMPILER_H | |
| 24 | + | #define STDEXT_COMPILER_H | |
| 25 | + | ||
| 26 | + | #ifdef WIN32 | |
| 27 | + | #include <winsock2.h> | |
| 28 | + | #endif | |
| 29 | + | ||
| 30 | + | #ifdef __clang__ | |
| 31 | + | // clang is supported | |
| 32 | + | #define BUILD_COMPILER "clang " __VERSION__ | |
| 33 | + | #elif defined(__GNUC__) | |
| 34 | + | #if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |
| 35 | + | #error "Sorry, you need gcc 4.6 or greater to compile." | |
| 36 | + | #endif | |
| 37 | + | #define BUILD_COMPILER "gcc " __VERSION__ | |
| 38 | + | #elif defined(_MSC_VER) | |
| 39 | + | #if _MSC_VER < 1800 | |
| 40 | + | #error "You need Visual Studio 2013 or greater to compile." | |
| 41 | + | #endif | |
| 42 | + | #pragma warning(disable:4244) // conversion from 'A' to 'B', possible loss of data | |
| 43 | + | #pragma warning(disable:4267) // '?' : conversion from 'A' to 'B', possible loss of data | |
| 44 | + | #pragma warning(disable:4305) // 'initializing' : truncation from 'A' to 'B' | |
| 45 | + | #pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned | |
| 46 | + | #pragma warning(disable:4800) // 'A' : forcing value to bool 'true' or 'false' (performance warning) | |
| 47 | + | #pragma warning(disable:4996) // depracated warning as error | |
| 48 | + | ||
| 49 | + | #if _MSC_VER == 1912 || _MSC_VER == 1911 || _MSC_VER == 1910 | |
| 50 | + | #define BUILD_COMPILER "Visual Studio 2017" | |
| 51 | + | #elif _MSC_VER == 1900 | |
| 52 | + | #define BUILD_COMPILER "Visual Studio 2015" | |
| 53 | + | #elif _MSC_VER == 1800 | |
| 54 | + | #define BUILD_COMPILER "Visual Studio 2013" | |
| 55 | + | #else | |
| 56 | + | #define BUILD_COMPILER "Visual Studio" | |
| 57 | + | #endif | |
| 58 | + | ||
| 59 | + | #define __PRETTY_FUNCTION__ __FUNCDNAME__ | |
| 60 | + | #else | |
| 61 | + | #error "Compiler not supported." | |
| 62 | + | #endif | |
| 63 | + | ||
| 64 | + | /// Branch Prediction. See the GCC Manual for more information. | |
| 65 | + | /// NB: These are used when speed is need most; do not use in normal | |
| 66 | + | /// code, they may slow down stuff. | |
| 67 | + | #if defined(__clang__) || defined(__GNUC__) | |
| 68 | + | #define likely(x) __builtin_expect(!!(x), 1) | |
| 69 | + | #define unlikely(x) __builtin_expect(!!(x), 0) | |
| 70 | + | #else | |
| 71 | + | #define likely(x) (x) | |
| 72 | + | #define unlikely(x) (x) | |
| 73 | + | #endif | |
| 74 | + | ||
| 75 | + | #if !defined(_MSC_VER) && !defined(__GXX_EXPERIMENTAL_CXX0X__) | |
| 76 | + | #error "C++0x is required to compile this application. Try updating your compiler." | |
| 77 | + | #endif | |
| 78 | + | ||
| 79 | + | #endif |
| @@ -0,0 +1,64 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #include "demangle.h" | |
| 24 | + | ||
| 25 | + | #ifdef _MSC_VER | |
| 26 | + | ||
| 27 | + | #include <winsock2.h> | |
| 28 | + | #include <windows.h> | |
| 29 | + | ||
| 30 | + | #pragma warning (push) | |
| 31 | + | #pragma warning (disable:4091) // warning C4091: 'typedef ': ignored on left of '' when no variable is declared | |
| 32 | + | #include <dbghelp.h> | |
| 33 | + | #pragma warning (pop) | |
| 34 | + | ||
| 35 | + | #else | |
| 36 | + | ||
| 37 | + | #include <cxxabi.h> | |
| 38 | + | #include <cstring> | |
| 39 | + | #include <cstdlib> | |
| 40 | + | ||
| 41 | + | #endif | |
| 42 | + | ||
| 43 | + | namespace stdext { | |
| 44 | + | ||
| 45 | + | const char* demangle_name(const char* name) | |
| 46 | + | { | |
| 47 | + | #ifdef _MSC_VER | |
| 48 | + | static char buffer[1024]; | |
| 49 | + | UnDecorateSymbolName(name, buffer, sizeof(buffer), UNDNAME_COMPLETE); | |
| 50 | + | return buffer; | |
| 51 | + | #else | |
| 52 | + | size_t len; | |
| 53 | + | int status; | |
| 54 | + | static char buffer[1024]; | |
| 55 | + | char* demangled = abi::__cxa_demangle(name, 0, &len, &status); | |
| 56 | + | if(demangled) { | |
| 57 | + | strcpy(buffer, demangled); | |
| 58 | + | free(demangled); | |
| 59 | + | } | |
| 60 | + | return buffer; | |
| 61 | + | #endif | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | } |
| @@ -0,0 +1,48 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_DEMANGLE_H | |
| 24 | + | #define STDEXT_DEMANGLE_H | |
| 25 | + | ||
| 26 | + | #include <typeinfo> | |
| 27 | + | #include <string> | |
| 28 | + | ||
| 29 | + | namespace stdext { | |
| 30 | + | ||
| 31 | + | /// Demangle names for GNU g++ compiler | |
| 32 | + | const char* demangle_name(const char* name); | |
| 33 | + | ||
| 34 | + | /// Returns the name of a class | |
| 35 | + | template<typename T> std::string demangle_class() { | |
| 36 | + | #ifdef _MSC_VER | |
| 37 | + | return demangle_name(typeid(T).name()) + 6; | |
| 38 | + | #else | |
| 39 | + | return demangle_name(typeid(T).name()); | |
| 40 | + | #endif | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | /// Returns the name of a type | |
| 44 | + | template<typename T> std::string demangle_type() { return demangle_name(typeid(T).name()); } | |
| 45 | + | ||
| 46 | + | } | |
| 47 | + | ||
| 48 | + | #endif |
| @@ -0,0 +1,42 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_DUMPER_H | |
| 24 | + | #define STDEXT_DUMPER_H | |
| 25 | + | ||
| 26 | + | #include <iostream> | |
| 27 | + | ||
| 28 | + | namespace stdext { | |
| 29 | + | ||
| 30 | + | static struct { | |
| 31 | + | struct dumper_dummy { | |
| 32 | + | ~dumper_dummy() { std::cout << std::endl; } | |
| 33 | + | template<class T> dumper_dummy& operator<<(const T& v) { std::cout << v << " "; return *this; } | |
| 34 | + | }; | |
| 35 | + | template<class T> dumper_dummy operator<<(const T& v) const { dumper_dummy d; d << v; return d; } | |
| 36 | + | } dump; | |
| 37 | + | ||
| 38 | + | } | |
| 39 | + | ||
| 40 | + | using stdext::dump; | |
| 41 | + | ||
| 42 | + | #endif |
| @@ -0,0 +1,67 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_DYNAMICSTORAGE_H | |
| 24 | + | #define STDEXT_DYNAMICSTORAGE_H | |
| 25 | + | ||
| 26 | + | #include "types.h" | |
| 27 | + | #include "any.h" | |
| 28 | + | #include <unordered_map> | |
| 29 | + | ||
| 30 | + | namespace stdext { | |
| 31 | + | ||
| 32 | + | template<typename Key> | |
| 33 | + | class dynamic_storage { | |
| 34 | + | public: | |
| 35 | + | template<typename T> void set(const Key& k, const T& value) { | |
| 36 | + | if(m_data.size() <= k) | |
| 37 | + | m_data.resize(k+1); | |
| 38 | + | m_data[k] = value; | |
| 39 | + | } | |
| 40 | + | bool remove(const Key& k) { | |
| 41 | + | if(m_data.size() < k) | |
| 42 | + | return false; | |
| 43 | + | if(m_data[k].empty()) | |
| 44 | + | return false; | |
| 45 | + | m_data[k] = any(); | |
| 46 | + | return true; | |
| 47 | + | } | |
| 48 | + | template<typename T> T get(const Key& k) const { return has(k) ? any_cast<T>(m_data[k]) : T(); } | |
| 49 | + | bool has(const Key& k) const { return k < m_data.size() && !m_data[k].empty(); } | |
| 50 | + | ||
| 51 | + | std::size_t size() const { | |
| 52 | + | std::size_t count = 0; | |
| 53 | + | for(std::size_t i=0;i<m_data.size();++i) | |
| 54 | + | if(!m_data[i].empty()) | |
| 55 | + | count++; | |
| 56 | + | return count; | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | void clear() { m_data.clear(); } | |
| 60 | + | ||
| 61 | + | private: | |
| 62 | + | std::vector<any> m_data; | |
| 63 | + | }; | |
| 64 | + | ||
| 65 | + | } | |
| 66 | + | ||
| 67 | + | #endif |
| @@ -0,0 +1,47 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_EXCEPTION_H | |
| 24 | + | #define STDEXT_EXCEPTION_H | |
| 25 | + | ||
| 26 | + | #include <exception> | |
| 27 | + | #include <string> | |
| 28 | + | ||
| 29 | + | namespace stdext { | |
| 30 | + | ||
| 31 | + | class exception : public std::exception | |
| 32 | + | { | |
| 33 | + | public: | |
| 34 | + | exception() { } | |
| 35 | + | exception(const std::string& what) : m_what(what) { } | |
| 36 | + | virtual ~exception() throw() { }; | |
| 37 | + | virtual const char* what() const throw() { return m_what.c_str(); } | |
| 38 | + | protected: | |
| 39 | + | std::string m_what; | |
| 40 | + | }; | |
| 41 | + | ||
| 42 | + | /// Throws a generic exception | |
| 43 | + | inline void throw_exception(const std::string& what) { throw exception(what); } | |
| 44 | + | ||
| 45 | + | } | |
| 46 | + | ||
| 47 | + | #endif |
| @@ -0,0 +1,12 @@ | |||
| 1 | + | #pragma once | |
| 2 | + | ||
| 3 | + | namespace stdext { | |
| 4 | + | ||
| 5 | + | static int fastrand() | |
| 6 | + | { | |
| 7 | + | static int g_seed = (214013 + 2531011); | |
| 8 | + | g_seed = (214013 * g_seed + 2531011); | |
| 9 | + | return (g_seed >> 16) & 0x7FFF; | |
| 10 | + | }; | |
| 11 | + | ||
| 12 | + | } |
| @@ -0,0 +1,100 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_FORMAT_H | |
| 24 | + | #define STDEXT_FORMAT_H | |
| 25 | + | ||
| 26 | + | #include "traits.h" | |
| 27 | + | ||
| 28 | + | #include <string> | |
| 29 | + | #include <cstdio> | |
| 30 | + | #include <tuple> | |
| 31 | + | #include <iostream> | |
| 32 | + | #include <sstream> | |
| 33 | + | #include <iomanip> | |
| 34 | + | ||
| 35 | + | namespace stdext { | |
| 36 | + | ||
| 37 | + | template<class T> void print_ostream(std::ostringstream& stream, const T& last) { stream << last; } | |
| 38 | + | template<class T, class... Args> | |
| 39 | + | void print_ostream(std::ostringstream& stream, const T& first, const Args&... rest) { stream << "\t" << first; print_ostream(stream, rest...); } | |
| 40 | + | template<class... T> | |
| 41 | + | ||
| 42 | + | // Utility for printing variables just like lua | |
| 43 | + | void print(const T&... args) { std::ostringstream buf; print_ostream(buf, args...); std::cout << buf.str() << std::endl; } | |
| 44 | + | ||
| 45 | + | template<typename T> | |
| 46 | + | typename std::enable_if<std::is_integral<T>::value || | |
| 47 | + | std::is_pointer<T>::value || | |
| 48 | + | std::is_floating_point<T>::value || | |
| 49 | + | std::is_enum<T>::value, T>::type sprintf_cast(const T& t) { return t; } | |
| 50 | + | inline const char *sprintf_cast(const char *s) { return s; } | |
| 51 | + | inline const char *sprintf_cast(const std::string& s) { return s.c_str(); } | |
| 52 | + | ||
| 53 | + | template<int N> struct expand_snprintf { | |
| 54 | + | template<typename Tuple, typename... Args> static int call(char *s, size_t maxlen, const char *format, const Tuple& tuple, const Args&... args) { | |
| 55 | + | return expand_snprintf<N-1>::call(s, maxlen, format, tuple, sprintf_cast(std::get<N-1>(tuple)), args...); }}; | |
| 56 | + | template<> struct expand_snprintf<0> { | |
| 57 | + | template<typename Tuple, typename... Args> static int call(char *s, size_t maxlen, const char *format, const Tuple& tuple, const Args&... args) { | |
| 58 | + | #ifdef _MSC_VER | |
| 59 | + | return _snprintf(s, maxlen, format, args...); | |
| 60 | + | #else | |
| 61 | + | return snprintf(s, maxlen, format, args...); | |
| 62 | + | #endif | |
| 63 | + | } | |
| 64 | + | }; | |
| 65 | + | ||
| 66 | + | // Improved snprintf that accepts std::string and other types | |
| 67 | + | template<typename... Args> | |
| 68 | + | int snprintf(char *s, size_t maxlen, const char *format, const Args&... args) { | |
| 69 | + | std::tuple<typename replace_extent<Args>::type...> tuple(args...); | |
| 70 | + | return expand_snprintf<std::tuple_size<decltype(tuple)>::value>::call(s, maxlen, format, tuple); | |
| 71 | + | } | |
| 72 | + | ||
| 73 | + | template<typename... Args> | |
| 74 | + | inline int snprintf(char *s, size_t maxlen, const char *format) { | |
| 75 | + | std::strncpy(s, format, maxlen); | |
| 76 | + | s[maxlen-1] = 0; | |
| 77 | + | return strlen(s); | |
| 78 | + | } | |
| 79 | + | ||
| 80 | + | template<typename... Args> | |
| 81 | + | inline std::string format() { return std::string(); } | |
| 82 | + | ||
| 83 | + | template<typename... Args> | |
| 84 | + | inline std::string format(const std::string& format) { return format; } | |
| 85 | + | ||
| 86 | + | // Format strings with the sprintf style, accepting std::string and string convertible types for %s | |
| 87 | + | template<typename... Args> | |
| 88 | + | std::string format(const std::string& format, const Args&... args) { | |
| 89 | + | int n = snprintf(NULL, 0, format.c_str(), args...); | |
| 90 | + | VALIDATE(n != -1); | |
| 91 | + | std::string buffer(n + 1, '\0'); | |
| 92 | + | n = snprintf(&buffer[0], buffer.size(), format.c_str(), args...); | |
| 93 | + | VALIDATE(n != -1); | |
| 94 | + | buffer.resize(n); | |
| 95 | + | return buffer; | |
| 96 | + | } | |
| 97 | + | ||
| 98 | + | } | |
| 99 | + | ||
| 100 | + | #endif |
| @@ -0,0 +1,69 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #include "math.h" | |
| 24 | + | #include <random> | |
| 25 | + | ||
| 26 | + | #ifdef _MSC_VER | |
| 27 | + | #pragma warning(disable:4267) // '?' : conversion from 'A' to 'B', possible loss of data | |
| 28 | + | #endif | |
| 29 | + | ||
| 30 | + | namespace stdext { | |
| 31 | + | ||
| 32 | + | uint32_t adler32(const uint8_t *buffer, size_t size) { | |
| 33 | + | size_t a = 1, b = 0, tlen; | |
| 34 | + | while(size > 0) { | |
| 35 | + | tlen = size > 5552 ? 5552 : size; | |
| 36 | + | size -= tlen; | |
| 37 | + | do { | |
| 38 | + | a += *buffer++; | |
| 39 | + | b += a; | |
| 40 | + | } while (--tlen); | |
| 41 | + | ||
| 42 | + | a %= 65521; | |
| 43 | + | b %= 65521; | |
| 44 | + | } | |
| 45 | + | return (b << 16) | a; | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | long random_range(long min, long max) | |
| 49 | + | { | |
| 50 | + | static std::random_device rd; | |
| 51 | + | static std::mt19937 gen(rd()); | |
| 52 | + | static std::uniform_int_distribution<long> dis(0, 2147483647); | |
| 53 | + | return min + (dis(gen) % (max - min + 1)); | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | float random_range(float min, float max) | |
| 57 | + | { | |
| 58 | + | static std::random_device rd; | |
| 59 | + | static std::mt19937 gen(rd()); | |
| 60 | + | static std::uniform_real_distribution<float> dis(0.0, 1.0); | |
| 61 | + | return min + (max - min)*dis(gen); | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | double round(double r) | |
| 65 | + | { | |
| 66 | + | return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | } |
| @@ -0,0 +1,62 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_MATH_H | |
| 24 | + | #define STDEXT_MATH_H | |
| 25 | + | ||
| 26 | + | #include <algorithm> | |
| 27 | + | #include "types.h" | |
| 28 | + | ||
| 29 | + | namespace stdext { | |
| 30 | + | ||
| 31 | + | inline bool is_power_of_two(size_t v) { return ((v != 0) && !(v & (v - 1))); } | |
| 32 | + | inline size_t to_power_of_two(size_t v) { if(v == 0) return 0; size_t r = 1; while(r < v && r != 0xffffffff) r <<= 1; return r; } | |
| 33 | + | ||
| 34 | + | inline uint16_t readULE16(const uchar *addr) { return (uint16_t)addr[1] << 8 | addr[0]; } | |
| 35 | + | inline uint32_t readULE32(const uchar *addr) { return (uint32_t)readULE16(addr + 2) << 16 | readULE16(addr); } | |
| 36 | + | inline uint64_t readULE64(const uchar *addr) { return (uint64_t)readULE32(addr + 4) << 32 | readULE32(addr); } | |
| 37 | + | ||
| 38 | + | inline void writeULE16(uchar *addr, uint16_t value) { addr[1] = value >> 8; addr[0] = (uint8_t)value; } | |
| 39 | + | inline void writeULE32(uchar *addr, uint32_t value) { writeULE16(addr + 2, value >> 16); writeULE16(addr, (uint16_t)value); } | |
| 40 | + | inline void writeULE64(uchar *addr, uint64_t value) { writeULE32(addr + 4, value >> 32); writeULE32(addr, (uint32_t)value); } | |
| 41 | + | ||
| 42 | + | inline int16_t readSLE16(const uchar *addr) { return (int16_t)addr[1] << 8 | addr[0]; } | |
| 43 | + | inline int32_t readSLE32(const uchar *addr) { return (int32_t)readSLE16(addr + 2) << 16 | readSLE16(addr); } | |
| 44 | + | inline int64_t readSLE64(const uchar *addr) { return (int64_t)readSLE32(addr + 4) << 32 | readSLE32(addr); } | |
| 45 | + | ||
| 46 | + | inline void writeSLE16(uchar *addr, int16_t value) { addr[1] = value >> 8; addr[0] = (int8_t)value; } | |
| 47 | + | inline void writeSLE32(uchar *addr, int32_t value) { writeSLE16(addr + 2, value >> 16); writeSLE16(addr, (int16_t)value); } | |
| 48 | + | inline void writeSLE64(uchar *addr, int64_t value) { writeSLE32(addr + 4, value >> 32); writeSLE32(addr, (int32_t)value); } | |
| 49 | + | ||
| 50 | + | uint32_t adler32(const uint8_t *buffer, size_t size); | |
| 51 | + | ||
| 52 | + | long random_range(long min, long max); | |
| 53 | + | float random_range(float min, float max); | |
| 54 | + | ||
| 55 | + | double round(double r); | |
| 56 | + | ||
| 57 | + | template<typename T> | |
| 58 | + | T clamp(T x, T min, T max) { return std::max<T>(min, std::min<T>(x, max)); } | |
| 59 | + | ||
| 60 | + | } | |
| 61 | + | ||
| 62 | + | #endif |
| @@ -0,0 +1,60 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #include "net.h" | |
| 24 | + | #include <boost/lexical_cast.hpp> | |
| 25 | + | #include <boost/algorithm/string.hpp> | |
| 26 | + | #include <boost/asio/ip/address_v4.hpp> | |
| 27 | + | ||
| 28 | + | namespace stdext { | |
| 29 | + | ||
| 30 | + | std::string ip_to_string(uint32 ip) | |
| 31 | + | { | |
| 32 | + | ip = boost::asio::detail::socket_ops::network_to_host_long(ip); | |
| 33 | + | boost::asio::ip::address_v4 address_v4 = boost::asio::ip::address_v4(ip); | |
| 34 | + | return address_v4.to_string(); | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | uint32 string_to_ip(const std::string& string) | |
| 38 | + | { | |
| 39 | + | boost::asio::ip::address_v4 address_v4 = boost::asio::ip::address_v4::from_string(string); | |
| 40 | + | return boost::asio::detail::socket_ops::host_to_network_long(address_v4.to_ulong()); | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | std::vector<uint32> listSubnetAddresses(uint32 address, uint8 mask) | |
| 44 | + | { | |
| 45 | + | std::vector<uint32> list; | |
| 46 | + | if(mask < 32) { | |
| 47 | + | uint32 bitmask = (0xFFFFFFFF >> mask); | |
| 48 | + | for(uint32 i = 0; i <= bitmask; i++) { | |
| 49 | + | uint32 ip = boost::asio::detail::socket_ops::host_to_network_long((boost::asio::detail::socket_ops::network_to_host_long(address) & (~bitmask)) | i); | |
| 50 | + | if((ip >> 24) != 0 && (ip >> 24) != 0xFF) | |
| 51 | + | list.push_back(ip); | |
| 52 | + | } | |
| 53 | + | } | |
| 54 | + | else | |
| 55 | + | list.push_back(address); | |
| 56 | + | ||
| 57 | + | return list; | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | } |
| @@ -0,0 +1,36 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_NET_H | |
| 24 | + | #define STDEXT_NET_H | |
| 25 | + | ||
| 26 | + | #include "types.h" | |
| 27 | + | #include <string> | |
| 28 | + | #include <vector> | |
| 29 | + | ||
| 30 | + | namespace stdext { | |
| 31 | + | std::string ip_to_string(uint32 ip); | |
| 32 | + | uint32 string_to_ip(const std::string& string); | |
| 33 | + | std::vector<uint32> listSubnetAddresses(uint32 address, uint8 mask); | |
| 34 | + | } | |
| 35 | + | ||
| 36 | + | #endif |
| @@ -0,0 +1,117 @@ | |||
| 1 | + | /* | |
| 2 | + | * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient> | |
| 3 | + | * | |
| 4 | + | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 | + | * of this software and associated documentation files (the "Software"), to deal | |
| 6 | + | * in the Software without restriction, including without limitation the rights | |
| 7 | + | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 8 | + | * copies of the Software, and to permit persons to whom the Software is | |
| 9 | + | * furnished to do so, subject to the following conditions: | |
| 10 | + | * | |
| 11 | + | * The above copyright notice and this permission notice shall be included in | |
| 12 | + | * all copies or substantial portions of the Software. | |
| 13 | + | * | |
| 14 | + | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 | + | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 | + | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 19 | + | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | + | * THE SOFTWARE. | |
| 21 | + | */ | |
| 22 | + | ||
| 23 | + | #ifndef STDEXT_PACKEDANY_H | |
| 24 | + | #define STDEXT_PACKEDANY_H | |
| 25 | + | ||
| 26 | + | #include <framework/global.h> | |
| 27 | + | #include <algorithm> | |
| 28 | + | #include <type_traits> | |
| 29 | + | #include <typeinfo> | |
| 30 | + | ||
| 31 | + | namespace stdext { | |
| 32 | + | ||
| 33 | + | // disable memory alignment | |
| 34 | + | #pragma pack(push,1) | |
| 35 | + | ||
| 36 | + | template<typename T> | |
| 37 | + | struct can_pack_in_any : std::integral_constant<bool, | |
| 38 | + | (sizeof(T) <= sizeof(void*) && std::is_trivial<T>::value)> {}; | |
| 39 | + | ||
| 40 | + | // improved to use less memory | |
| 41 | + | class packed_any { | |
| 42 | + | public: | |
| 43 | + | struct placeholder { | |
| 44 | + | virtual ~placeholder() { } | |
| 45 | + | virtual const std::type_info& type() const = 0; | |
| 46 | + | virtual placeholder* clone() const = 0; | |
| 47 | + | }; | |
| 48 | + | ||
| 49 | + | template<typename T> | |
| 50 | + | struct holder : public placeholder { | |
| 51 | + | holder(const T& value) : held(value) { } | |
| 52 | + | const std::type_info& type() const { return typeid(T); } | |
| 53 | + | placeholder* clone() const { return new holder(held); } | |
| 54 | + | T held; | |
| 55 | + | private: | |
| 56 | + | holder& operator=(const holder &); | |
| 57 | + | }; | |
| 58 | + | ||
| 59 | + | placeholder* content; | |
| 60 | + | bool scalar; | |
| 61 | + | ||
| 62 | + | packed_any() : | |
| 63 | + | content(nullptr), scalar(false) { } | |
| 64 | + | packed_any(const packed_any& other) : | |
| 65 | + | content(!other.scalar && other.content ? other.content->clone() : other.content), | |
| 66 | + | scalar(other.scalar) { } | |
| 67 | + | template<typename T> | |
| 68 | + | packed_any(const T& value, typename std::enable_if<(can_pack_in_any<T>::value)>::type* = nullptr) : | |
| 69 | + | content(reinterpret_cast<placeholder*>(static_cast<std::size_t>(value))), scalar(true) { } | |
| 70 | + | template<typename T> | |
| 71 | + | packed_any(const T& value, typename std::enable_if<!(can_pack_in_any<T>::value)>::type* = nullptr) : | |
| 72 | + | content(new holder<T>(value)), scalar(false) { } | |
| 73 | + | ~packed_any() | |
| 74 | + | { if(!scalar && content) delete content; } | |
| 75 | + | ||
| 76 | + | packed_any& swap(packed_any& rhs) { std::swap(content, rhs.content); std::swap(scalar, rhs.scalar); return *this; } | |
| 77 | + | ||
| 78 | + | template<typename T> packed_any& operator=(const T& rhs) { packed_any(rhs).swap(*this); return *this; } | |
| 79 | + | packed_any& operator=(packed_any rhs) { rhs.swap(*this); return *this; } | |
| 80 | + | ||
| 81 | + | bool empty() const { return !scalar && !content; } | |
| 82 | + | template<typename T> T cast() const; | |
| 83 | + | const std::type_info& type() const { | |
| 84 | + | if(!scalar) | |
| 85 | + | return content ? content->type() : typeid(void); | |
| 86 | + | else | |
| 87 | + | return typeid(std::size_t); | |
| 88 | + | } | |
| 89 | + | }; | |
| 90 | + | ||
| 91 | + | template<typename T> | |
| 92 | + | typename std::enable_if<can_pack_in_any<T>::value, T>::type | |
| 93 | + | packed_any_cast(const packed_any& operand) { | |
| 94 | + | VALIDATE(operand.scalar); | |
| 95 | + | union { | |
| 96 | + | T v; | |
| 97 | + | packed_any::placeholder* content; | |
| 98 | + | }; | |
| 99 | + | content = operand.content; | |
| 100 | + | return v; | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | template<typename T> | |
| 104 | + | typename std::enable_if<!can_pack_in_any<T>::value, T>::type | |
| 105 | + | packed_any_cast(const packed_any& operand) { | |
| 106 | + | VALIDATE(operand.type() == typeid(T)); | |
| 107 | + | return static_cast<packed_any::holder<T>*>(operand.content)->held; | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | template<typename T> T packed_any::cast() const { return packed_any_cast<T>(*this); } | |
| 111 | + | ||
| 112 | + | // restore memory alignment | |
| 113 | + | #pragma pack(pop) | |
| 114 | + | ||
| 115 | + | } | |
| 116 | + | ||
| 117 | + | #endif |