Update to 14.0-beta1
This commit is contained in:
Vendored
+5
-1
@@ -1,5 +1,9 @@
|
||||
add_subdirectory(catch2)
|
||||
add_subdirectory(fmt)
|
||||
add_subdirectory(icu)
|
||||
add_subdirectory(md5)
|
||||
add_subdirectory(monocypher)
|
||||
add_subdirectory(squirrel)
|
||||
add_subdirectory(nlohmann)
|
||||
add_subdirectory(opengl)
|
||||
add_subdirectory(os2)
|
||||
add_subdirectory(openttd_social_integration_api)
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
The files in this directory are not licensed under the same terms as the
|
||||
rest of OpenTTD. Licensing details can be found in OpenTTD's readme.txt
|
||||
rest of OpenTTD. Licensing details can be found in OpenTTD's README.md
|
||||
and in this directory or subdirectories as well.
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
add_files(
|
||||
catch.hpp
|
||||
)
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
Vendored
+17976
File diff suppressed because it is too large
Load Diff
Vendored
+4
@@ -1,5 +1,9 @@
|
||||
add_files(
|
||||
chrono.h
|
||||
core.h
|
||||
format.h
|
||||
format-inl.h
|
||||
ostream.h
|
||||
ranges.h
|
||||
std.h
|
||||
)
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2012 - present, Victor Zverovich
|
||||
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
Vendored
+2240
File diff suppressed because it is too large
Load Diff
Vendored
+2192
-1350
File diff suppressed because it is too large
Load Diff
Vendored
+1283
-2411
File diff suppressed because it is too large
Load Diff
Vendored
+3560
-2986
File diff suppressed because it is too large
Load Diff
Vendored
+245
@@ -0,0 +1,245 @@
|
||||
// Formatting library for C++ - std::ostream support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_OSTREAM_H_
|
||||
#define FMT_OSTREAM_H_
|
||||
|
||||
#include <fstream> // std::filebuf
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef __GLIBCXX__
|
||||
# include <ext/stdio_filebuf.h>
|
||||
# include <ext/stdio_sync_filebuf.h>
|
||||
# endif
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename Streambuf> class formatbuf : public Streambuf {
|
||||
private:
|
||||
using char_type = typename Streambuf::char_type;
|
||||
using streamsize = decltype(std::declval<Streambuf>().sputn(nullptr, 0));
|
||||
using int_type = typename Streambuf::int_type;
|
||||
using traits_type = typename Streambuf::traits_type;
|
||||
|
||||
buffer<char_type>& buffer_;
|
||||
|
||||
public:
|
||||
explicit formatbuf(buffer<char_type>& buf) : buffer_(buf) {}
|
||||
|
||||
protected:
|
||||
// The put area is always empty. This makes the implementation simpler and has
|
||||
// the advantage that the streambuf and the buffer are always in sync and
|
||||
// sputc never writes into uninitialized memory. A disadvantage is that each
|
||||
// call to sputc always results in a (virtual) call to overflow. There is no
|
||||
// disadvantage here for sputn since this always results in a call to xsputn.
|
||||
|
||||
auto overflow(int_type ch) -> int_type override {
|
||||
if (!traits_type::eq_int_type(ch, traits_type::eof()))
|
||||
buffer_.push_back(static_cast<char_type>(ch));
|
||||
return ch;
|
||||
}
|
||||
|
||||
auto xsputn(const char_type* s, streamsize count) -> streamsize override {
|
||||
buffer_.append(s, s + count);
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
// Generate a unique explicit instantion in every translation unit using a tag
|
||||
// type in an anonymous namespace.
|
||||
namespace {
|
||||
struct file_access_tag {};
|
||||
} // namespace
|
||||
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
|
||||
class file_access {
|
||||
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
|
||||
};
|
||||
|
||||
#if FMT_MSC_VERSION
|
||||
template class file_access<file_access_tag, std::filebuf,
|
||||
&std::filebuf::_Myfile>;
|
||||
auto get_file(std::filebuf&) -> FILE*;
|
||||
#endif
|
||||
|
||||
inline auto write_ostream_unicode(std::ostream& os, fmt::string_view data)
|
||||
-> bool {
|
||||
FILE* f = nullptr;
|
||||
#if FMT_MSC_VERSION
|
||||
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
|
||||
f = get_file(*buf);
|
||||
else
|
||||
return false;
|
||||
#elif defined(_WIN32) && defined(__GLIBCXX__)
|
||||
auto* rdbuf = os.rdbuf();
|
||||
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
|
||||
f = sfbuf->file();
|
||||
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
|
||||
f = fbuf->file();
|
||||
else
|
||||
return false;
|
||||
#else
|
||||
ignore_unused(os, data, f);
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
if (f) {
|
||||
int fd = _fileno(f);
|
||||
if (_isatty(fd)) {
|
||||
os.flush();
|
||||
return write_console(fd, data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
inline auto write_ostream_unicode(std::wostream&,
|
||||
fmt::basic_string_view<wchar_t>) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the content of buf to os.
|
||||
// It is a separate function rather than a part of vprint to simplify testing.
|
||||
template <typename Char>
|
||||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||
const Char* buf_data = buf.data();
|
||||
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
||||
unsigned_streamsize size = buf.size();
|
||||
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
|
||||
do {
|
||||
unsigned_streamsize n = size <= max_size ? size : max_size;
|
||||
os.write(buf_data, static_cast<std::streamsize>(n));
|
||||
buf_data += n;
|
||||
size -= n;
|
||||
} while (size != 0);
|
||||
}
|
||||
|
||||
template <typename Char, typename T>
|
||||
void format_value(buffer<Char>& buf, const T& value) {
|
||||
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
|
||||
auto&& output = std::basic_ostream<Char>(&format_buf);
|
||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
output.imbue(std::locale::classic()); // The default is always unlocalized.
|
||||
#endif
|
||||
output << value;
|
||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
}
|
||||
|
||||
template <typename T> struct streamed_view {
|
||||
const T& value;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||
template <typename Char>
|
||||
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
|
||||
void set_debug_format() = delete;
|
||||
|
||||
template <typename T, typename OutputIt>
|
||||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
|
||||
-> OutputIt {
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
detail::format_value(buffer, value);
|
||||
return formatter<basic_string_view<Char>, Char>::format(
|
||||
{buffer.data(), buffer.size()}, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
using ostream_formatter = basic_ostream_formatter<char>;
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<detail::streamed_view<T>, Char>
|
||||
: basic_ostream_formatter<Char> {
|
||||
template <typename OutputIt>
|
||||
auto format(detail::streamed_view<T> view,
|
||||
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
|
||||
return basic_ostream_formatter<Char>::format(view.value, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns a view that formats `value` via an ostream ``operator<<``.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print("Current thread id: {}\n",
|
||||
fmt::streamed(std::this_thread::get_id()));
|
||||
\endrst
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr auto streamed(const T& value) -> detail::streamed_view<T> {
|
||||
return {value};
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline void vprint_directly(std::ostream& os, string_view format_str,
|
||||
format_args args) {
|
||||
auto buffer = memory_buffer();
|
||||
detail::vformat_to(buffer, format_str, args);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_EXPORT template <typename Char>
|
||||
void vprint(std::basic_ostream<Char>& os,
|
||||
basic_string_view<type_identity_t<Char>> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
detail::vformat_to(buffer, format_str, args);
|
||||
if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return;
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the stream *os*.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print(cerr, "Don't {}!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
FMT_EXPORT template <typename... T>
|
||||
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||
const auto& vargs = fmt::make_format_args(args...);
|
||||
if (detail::is_utf8())
|
||||
vprint(os, fmt, vargs);
|
||||
else
|
||||
detail::vprint_directly(os, fmt, vargs);
|
||||
}
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename... Args>
|
||||
void print(std::wostream& os,
|
||||
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
|
||||
Args&&... args) {
|
||||
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
|
||||
}
|
||||
|
||||
FMT_EXPORT template <typename... T>
|
||||
void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||
fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename... Args>
|
||||
void println(std::wostream& os,
|
||||
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
|
||||
Args&&... args) {
|
||||
print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OSTREAM_H_
|
||||
Vendored
+738
@@ -0,0 +1,738 @@
|
||||
// Formatting library for C++ - range and tuple support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_RANGES_H_
|
||||
#define FMT_RANGES_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Range, typename OutputIt>
|
||||
auto copy(const Range& range, OutputIt out) -> OutputIt {
|
||||
for (auto it = range.begin(), end = range.end(); it != end; ++it)
|
||||
*out++ = *it;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename OutputIt>
|
||||
auto copy(const char* str, OutputIt out) -> OutputIt {
|
||||
while (*str) *out++ = *str++;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename OutputIt> auto copy(char ch, OutputIt out) -> OutputIt {
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt {
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Returns true if T has a std::string-like interface, like std::string_view.
|
||||
template <typename T> class is_std_string_like {
|
||||
template <typename U>
|
||||
static auto check(U* p)
|
||||
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
is_string<T>::value ||
|
||||
std::is_convertible<T, std_string_view<char>>::value ||
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
||||
|
||||
template <typename T> class is_map {
|
||||
template <typename U> static auto check(U*) -> typename U::mapped_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
#ifdef FMT_FORMAT_MAP_AS_LIST // DEPRECATED!
|
||||
static constexpr const bool value = false;
|
||||
#else
|
||||
static constexpr const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T> class is_set {
|
||||
template <typename U> static auto check(U*) -> typename U::key_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
#ifdef FMT_FORMAT_SET_AS_LIST // DEPRECATED!
|
||||
static constexpr const bool value = false;
|
||||
#else
|
||||
static constexpr const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename... Ts> struct conditional_helper {};
|
||||
|
||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||
|
||||
#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800
|
||||
|
||||
# define FMT_DECLTYPE_RETURN(val) \
|
||||
->decltype(val) { return val; } \
|
||||
static_assert( \
|
||||
true, "") // This makes it so that a semicolon is required after the
|
||||
// macro, which helps clang-format handle the formatting.
|
||||
|
||||
// C array overload
|
||||
template <typename T, std::size_t N>
|
||||
auto range_begin(const T (&arr)[N]) -> const T* {
|
||||
return arr;
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
auto range_end(const T (&arr)[N]) -> const T* {
|
||||
return arr + N;
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_member_fn_begin_end_t : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
|
||||
decltype(std::declval<T>().end())>>
|
||||
: std::true_type {};
|
||||
|
||||
// Member function overload
|
||||
template <typename T>
|
||||
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
|
||||
template <typename T>
|
||||
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
|
||||
|
||||
// ADL overload. Only participates in overload resolution if member functions
|
||||
// are not found.
|
||||
template <typename T>
|
||||
auto range_begin(T&& rng)
|
||||
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||
decltype(begin(static_cast<T&&>(rng)))> {
|
||||
return begin(static_cast<T&&>(rng));
|
||||
}
|
||||
template <typename T>
|
||||
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||
decltype(end(static_cast<T&&>(rng)))> {
|
||||
return end(static_cast<T&&>(rng));
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_const_begin_end : std::false_type {};
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_mutable_begin_end : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_const_begin_end<
|
||||
T,
|
||||
void_t<
|
||||
decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())),
|
||||
decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_mutable_begin_end<
|
||||
T, void_t<decltype(detail::range_begin(std::declval<T>())),
|
||||
decltype(detail::range_end(std::declval<T>())),
|
||||
// the extra int here is because older versions of MSVC don't
|
||||
// SFINAE properly unless there are distinct types
|
||||
int>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_range_<T, void>
|
||||
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
|
||||
has_mutable_begin_end<T>::value)> {};
|
||||
# undef FMT_DECLTYPE_RETURN
|
||||
#endif
|
||||
|
||||
// tuple_size and tuple_element check.
|
||||
template <typename T> class is_tuple_like_ {
|
||||
template <typename U>
|
||||
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
// Check for integer_sequence
|
||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
|
||||
template <typename T, T... N>
|
||||
using integer_sequence = std::integer_sequence<T, N...>;
|
||||
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
||||
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
|
||||
#else
|
||||
template <typename T, T... N> struct integer_sequence {
|
||||
using value_type = T;
|
||||
|
||||
static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); }
|
||||
};
|
||||
|
||||
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
|
||||
|
||||
template <typename T, size_t N, T... Ns>
|
||||
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
|
||||
template <typename T, T... Ns>
|
||||
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
|
||||
|
||||
template <size_t N>
|
||||
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
|
||||
|
||||
template <typename T, typename C, bool = is_tuple_like_<T>::value>
|
||||
class is_tuple_formattable_ {
|
||||
public:
|
||||
static constexpr const bool value = false;
|
||||
};
|
||||
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
|
||||
template <std::size_t... Is>
|
||||
static auto check2(index_sequence<Is...>,
|
||||
integer_sequence<bool, (Is == Is)...>) -> std::true_type;
|
||||
static auto check2(...) -> std::false_type;
|
||||
template <std::size_t... Is>
|
||||
static auto check(index_sequence<Is...>) -> decltype(check2(
|
||||
index_sequence<Is...>{},
|
||||
integer_sequence<bool,
|
||||
(is_formattable<typename std::tuple_element<Is, T>::type,
|
||||
C>::value)...>{}));
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
decltype(check(tuple_index_sequence<T>{}))::value;
|
||||
};
|
||||
|
||||
template <typename Tuple, typename F, size_t... Is>
|
||||
FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
|
||||
using std::get;
|
||||
// Using a free function get<Is>(Tuple) now.
|
||||
const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
|
||||
template <typename Tuple, typename F>
|
||||
FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
|
||||
for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
|
||||
std::forward<Tuple>(t), std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
|
||||
void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
|
||||
using std::get;
|
||||
const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
|
||||
template <typename Tuple1, typename Tuple2, typename F>
|
||||
void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
|
||||
for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
|
||||
std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
|
||||
std::forward<F>(f));
|
||||
}
|
||||
|
||||
namespace tuple {
|
||||
// Workaround a bug in MSVC 2019 (v140).
|
||||
template <typename Char, typename... T>
|
||||
using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
|
||||
|
||||
using std::get;
|
||||
template <typename Tuple, typename Char, std::size_t... Is>
|
||||
auto get_formatters(index_sequence<Is...>)
|
||||
-> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
|
||||
} // namespace tuple
|
||||
|
||||
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
|
||||
// Older MSVC doesn't get the reference type correctly for arrays.
|
||||
template <typename R> struct range_reference_type_impl {
|
||||
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
|
||||
using type = T&;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using range_reference_type = typename range_reference_type_impl<T>::type;
|
||||
#else
|
||||
template <typename Range>
|
||||
using range_reference_type =
|
||||
decltype(*detail::range_begin(std::declval<Range&>()));
|
||||
#endif
|
||||
|
||||
// We don't use the Range's value_type for anything, but we do need the Range's
|
||||
// reference type, with cv-ref stripped.
|
||||
template <typename Range>
|
||||
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
||||
|
||||
template <typename Formatter>
|
||||
FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
|
||||
-> decltype(f.set_debug_format(set)) {
|
||||
f.set_debug_format(set);
|
||||
}
|
||||
template <typename Formatter>
|
||||
FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
|
||||
|
||||
// These are not generic lambdas for compatibility with C++11.
|
||||
template <typename ParseContext> struct parse_empty_specs {
|
||||
template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
|
||||
f.parse(ctx);
|
||||
detail::maybe_set_debug_format(f, true);
|
||||
}
|
||||
ParseContext& ctx;
|
||||
};
|
||||
template <typename FormatContext> struct format_tuple_element {
|
||||
using char_type = typename FormatContext::char_type;
|
||||
|
||||
template <typename T>
|
||||
void operator()(const formatter<T, char_type>& f, const T& v) {
|
||||
if (i > 0)
|
||||
ctx.advance_to(detail::copy_str<char_type>(separator, ctx.out()));
|
||||
ctx.advance_to(f.format(v, ctx));
|
||||
++i;
|
||||
}
|
||||
|
||||
int i;
|
||||
FormatContext& ctx;
|
||||
basic_string_view<char_type> separator;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T> struct is_tuple_like {
|
||||
static constexpr const bool value =
|
||||
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename C> struct is_tuple_formattable {
|
||||
static constexpr const bool value =
|
||||
detail::is_tuple_formattable_<T, C>::value;
|
||||
};
|
||||
|
||||
template <typename Tuple, typename Char>
|
||||
struct formatter<Tuple, Char,
|
||||
enable_if_t<fmt::is_tuple_like<Tuple>::value &&
|
||||
fmt::is_tuple_formattable<Tuple, Char>::value>> {
|
||||
private:
|
||||
decltype(detail::tuple::get_formatters<Tuple, Char>(
|
||||
detail::tuple_index_sequence<Tuple>())) formatters_;
|
||||
|
||||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||
basic_string_view<Char> opening_bracket_ =
|
||||
detail::string_literal<Char, '('>{};
|
||||
basic_string_view<Char> closing_bracket_ =
|
||||
detail::string_literal<Char, ')'>{};
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR formatter() {}
|
||||
|
||||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||
separator_ = sep;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||
basic_string_view<Char> close) {
|
||||
opening_bracket_ = open;
|
||||
closing_bracket_ = close;
|
||||
}
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
auto it = ctx.begin();
|
||||
if (it != ctx.end() && *it != '}')
|
||||
FMT_THROW(format_error("invalid format specifier"));
|
||||
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const Tuple& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
ctx.advance_to(detail::copy_str<Char>(opening_bracket_, ctx.out()));
|
||||
detail::for_each2(
|
||||
formatters_, value,
|
||||
detail::format_tuple_element<FormatContext>{0, ctx, separator_});
|
||||
return detail::copy_str<Char>(closing_bracket_, ctx.out());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char> struct is_range {
|
||||
static constexpr const bool value =
|
||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||
!std::is_convertible<T, detail::std_string_view<Char>>::value;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename Context> struct range_mapper {
|
||||
using mapper = arg_mapper<Context>;
|
||||
|
||||
template <typename T,
|
||||
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||
static auto map(T&& value) -> T&& {
|
||||
return static_cast<T&&>(value);
|
||||
}
|
||||
template <typename T,
|
||||
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||
static auto map(T&& value)
|
||||
-> decltype(mapper().map(static_cast<T&&>(value))) {
|
||||
return mapper().map(static_cast<T&&>(value));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename Element>
|
||||
using range_formatter_type =
|
||||
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
|
||||
std::declval<Element>()))>,
|
||||
Char>;
|
||||
|
||||
template <typename R>
|
||||
using maybe_const_range =
|
||||
conditional_t<has_const_begin_end<R>::value, const R, R>;
|
||||
|
||||
// Workaround a bug in MSVC 2015 and earlier.
|
||||
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
|
||||
template <typename R, typename Char>
|
||||
struct is_formattable_delayed
|
||||
: is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
template <typename...> struct conjunction : std::true_type {};
|
||||
template <typename P> struct conjunction<P> : P {};
|
||||
template <typename P1, typename... Pn>
|
||||
struct conjunction<P1, Pn...>
|
||||
: conditional_t<bool(P1::value), conjunction<Pn...>, P1> {};
|
||||
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct range_formatter;
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct range_formatter<
|
||||
T, Char,
|
||||
enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
|
||||
is_formattable<T, Char>>::value>> {
|
||||
private:
|
||||
detail::range_formatter_type<Char, T> underlying_;
|
||||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||
basic_string_view<Char> opening_bracket_ =
|
||||
detail::string_literal<Char, '['>{};
|
||||
basic_string_view<Char> closing_bracket_ =
|
||||
detail::string_literal<Char, ']'>{};
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR range_formatter() {}
|
||||
|
||||
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
|
||||
return underlying_;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||
separator_ = sep;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||
basic_string_view<Char> close) {
|
||||
opening_bracket_ = open;
|
||||
closing_bracket_ = close;
|
||||
}
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
|
||||
if (it != end && *it == 'n') {
|
||||
set_brackets({}, {});
|
||||
++it;
|
||||
}
|
||||
|
||||
if (it != end && *it != '}') {
|
||||
if (*it != ':') FMT_THROW(format_error("invalid format specifier"));
|
||||
++it;
|
||||
} else {
|
||||
detail::maybe_set_debug_format(underlying_, true);
|
||||
}
|
||||
|
||||
ctx.advance_to(it);
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename R, typename FormatContext>
|
||||
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
detail::range_mapper<buffer_context<Char>> mapper;
|
||||
auto out = ctx.out();
|
||||
out = detail::copy_str<Char>(opening_bracket_, out);
|
||||
int i = 0;
|
||||
auto it = detail::range_begin(range);
|
||||
auto end = detail::range_end(range);
|
||||
for (; it != end; ++it) {
|
||||
if (i > 0) out = detail::copy_str<Char>(separator_, out);
|
||||
ctx.advance_to(out);
|
||||
auto&& item = *it;
|
||||
out = underlying_.format(mapper.map(item), ctx);
|
||||
++i;
|
||||
}
|
||||
out = detail::copy_str<Char>(closing_bracket_, out);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
enum class range_format { disabled, map, set, sequence, string, debug_string };
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct range_format_kind_
|
||||
: std::integral_constant<range_format,
|
||||
std::is_same<uncvref_type<T>, T>::value
|
||||
? range_format::disabled
|
||||
: is_map<T>::value ? range_format::map
|
||||
: is_set<T>::value ? range_format::set
|
||||
: range_format::sequence> {};
|
||||
|
||||
template <range_format K, typename R, typename Char, typename Enable = void>
|
||||
struct range_default_formatter;
|
||||
|
||||
template <range_format K>
|
||||
using range_format_constant = std::integral_constant<range_format, K>;
|
||||
|
||||
template <range_format K, typename R, typename Char>
|
||||
struct range_default_formatter<
|
||||
K, R, Char,
|
||||
enable_if_t<(K == range_format::sequence || K == range_format::map ||
|
||||
K == range_format::set)>> {
|
||||
using range_type = detail::maybe_const_range<R>;
|
||||
range_formatter<detail::uncvref_type<range_type>, Char> underlying_;
|
||||
|
||||
FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); }
|
||||
|
||||
FMT_CONSTEXPR void init(range_format_constant<range_format::set>) {
|
||||
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
|
||||
detail::string_literal<Char, '}'>{});
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void init(range_format_constant<range_format::map>) {
|
||||
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
|
||||
detail::string_literal<Char, '}'>{});
|
||||
underlying_.underlying().set_brackets({}, {});
|
||||
underlying_.underlying().set_separator(
|
||||
detail::string_literal<Char, ':', ' '>{});
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {}
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(range_type& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return underlying_.format(range, ctx);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct range_format_kind
|
||||
: conditional_t<
|
||||
is_range<T, Char>::value, detail::range_format_kind_<T>,
|
||||
std::integral_constant<range_format, range_format::disabled>> {};
|
||||
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value !=
|
||||
range_format::disabled>
|
||||
// Workaround a bug in MSVC 2015 and earlier.
|
||||
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
|
||||
,
|
||||
detail::is_formattable_delayed<R, Char>
|
||||
#endif
|
||||
>::value>>
|
||||
: detail::range_default_formatter<range_format_kind<R, Char>::value, R,
|
||||
Char> {
|
||||
};
|
||||
|
||||
template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
||||
const std::tuple<T...>& tuple;
|
||||
basic_string_view<Char> sep;
|
||||
|
||||
tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
|
||||
: tuple(t), sep{s} {}
|
||||
};
|
||||
|
||||
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
|
||||
// support in tuple_join. It is disabled by default because of issues with
|
||||
// the dynamic width and precision.
|
||||
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
|
||||
# define FMT_TUPLE_JOIN_SPECIFIERS 0
|
||||
#endif
|
||||
|
||||
template <typename Char, typename... T>
|
||||
struct formatter<tuple_join_view<Char, T...>, Char> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const tuple_join_view<Char, T...>& value,
|
||||
FormatContext& ctx) const -> typename FormatContext::iterator {
|
||||
return do_format(value, ctx,
|
||||
std::integral_constant<size_t, sizeof...(T)>());
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
|
||||
std::integral_constant<size_t, 0>)
|
||||
-> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename ParseContext, size_t N>
|
||||
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
|
||||
std::integral_constant<size_t, N>)
|
||||
-> decltype(ctx.begin()) {
|
||||
auto end = ctx.begin();
|
||||
#if FMT_TUPLE_JOIN_SPECIFIERS
|
||||
end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
|
||||
if (N > 1) {
|
||||
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
|
||||
if (end != end1)
|
||||
FMT_THROW(format_error("incompatible format specs for tuple elements"));
|
||||
}
|
||||
#endif
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
|
||||
std::integral_constant<size_t, 0>) const ->
|
||||
typename FormatContext::iterator {
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
template <typename FormatContext, size_t N>
|
||||
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
||||
std::integral_constant<size_t, N>) const ->
|
||||
typename FormatContext::iterator {
|
||||
auto out = std::get<sizeof...(T) - N>(formatters_)
|
||||
.format(std::get<sizeof...(T) - N>(value.tuple), ctx);
|
||||
if (N > 1) {
|
||||
out = std::copy(value.sep.begin(), value.sep.end(), out);
|
||||
ctx.advance_to(out);
|
||||
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
// Check if T has an interface like a container adaptor (e.g. std::stack,
|
||||
// std::queue, std::priority_queue).
|
||||
template <typename T> class is_container_adaptor_like {
|
||||
template <typename U> static auto check(U* p) -> typename U::container_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename Container> struct all {
|
||||
const Container& c;
|
||||
auto begin() const -> typename Container::const_iterator { return c.begin(); }
|
||||
auto end() const -> typename Container::const_iterator { return c.end(); }
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<
|
||||
T, Char,
|
||||
enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
|
||||
bool_constant<range_format_kind<T, Char>::value ==
|
||||
range_format::disabled>>::value>>
|
||||
: formatter<detail::all<typename T::container_type>, Char> {
|
||||
using all = detail::all<typename T::container_type>;
|
||||
template <typename FormatContext>
|
||||
auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
struct getter : T {
|
||||
static auto get(const T& t) -> all {
|
||||
return {t.*(&getter::c)}; // Access c through the derived class.
|
||||
}
|
||||
};
|
||||
return formatter<all>::format(getter::get(t), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns an object that formats `tuple` with elements separated by `sep`.
|
||||
|
||||
**Example**::
|
||||
|
||||
std::tuple<int, char> t = {1, 'a'};
|
||||
fmt::print("{}", fmt::join(t, ", "));
|
||||
// Output: "1, a"
|
||||
\endrst
|
||||
*/
|
||||
template <typename... T>
|
||||
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
|
||||
-> tuple_join_view<char, T...> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
|
||||
basic_string_view<wchar_t> sep)
|
||||
-> tuple_join_view<wchar_t, T...> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns an object that formats `initializer_list` with elements separated by
|
||||
`sep`.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print("{}", fmt::join({1, 2, 3}, ", "));
|
||||
// Output: "1, 2, 3"
|
||||
\endrst
|
||||
*/
|
||||
template <typename T>
|
||||
auto join(std::initializer_list<T> list, string_view sep)
|
||||
-> join_view<const T*, const T*> {
|
||||
return join(std::begin(list), std::end(list), sep);
|
||||
}
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_RANGES_H_
|
||||
Vendored
+537
@@ -0,0 +1,537 @@
|
||||
// Formatting library for C++ - formatters for standard library types
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_STD_H_
|
||||
#define FMT_STD_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "format.h"
|
||||
#include "ostream.h"
|
||||
|
||||
#if FMT_HAS_INCLUDE(<version>)
|
||||
# include <version>
|
||||
#endif
|
||||
// Checking FMT_CPLUSPLUS for warning suppression in MSVC.
|
||||
#if FMT_CPLUSPLUS >= 201703L
|
||||
# if FMT_HAS_INCLUDE(<filesystem>)
|
||||
# include <filesystem>
|
||||
# endif
|
||||
# if FMT_HAS_INCLUDE(<variant>)
|
||||
# include <variant>
|
||||
# endif
|
||||
# if FMT_HAS_INCLUDE(<optional>)
|
||||
# include <optional>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>)
|
||||
# include <source_location>
|
||||
#endif
|
||||
|
||||
// GCC 4 does not support FMT_HAS_INCLUDE.
|
||||
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
|
||||
# include <cxxabi.h>
|
||||
// Android NDK with gabi++ library on some architectures does not implement
|
||||
// abi::__cxa_demangle().
|
||||
# ifndef __GABIXX_CXXABI_H__
|
||||
# define FMT_HAS_ABI_CXA_DEMANGLE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Check if typeid is available.
|
||||
#ifndef FMT_USE_TYPEID
|
||||
// __RTTI is for EDG compilers. In MSVC typeid is available without RTTI.
|
||||
# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \
|
||||
defined(__INTEL_RTTI__) || defined(__RTTI)
|
||||
# define FMT_USE_TYPEID 1
|
||||
# else
|
||||
# define FMT_USE_TYPEID 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined.
|
||||
#ifndef FMT_CPP_LIB_FILESYSTEM
|
||||
# ifdef __cpp_lib_filesystem
|
||||
# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
|
||||
# else
|
||||
# define FMT_CPP_LIB_FILESYSTEM 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FMT_CPP_LIB_VARIANT
|
||||
# ifdef __cpp_lib_variant
|
||||
# define FMT_CPP_LIB_VARIANT __cpp_lib_variant
|
||||
# else
|
||||
# define FMT_CPP_LIB_VARIANT 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_CPP_LIB_FILESYSTEM
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Char, typename PathChar>
|
||||
auto get_path_string(const std::filesystem::path& p,
|
||||
const std::basic_string<PathChar>& native) {
|
||||
if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>)
|
||||
return to_utf8<wchar_t>(native, to_utf8_error_policy::replace);
|
||||
else
|
||||
return p.string<Char>();
|
||||
}
|
||||
|
||||
template <typename Char, typename PathChar>
|
||||
void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||
const std::filesystem::path& p,
|
||||
const std::basic_string<PathChar>& native) {
|
||||
if constexpr (std::is_same_v<Char, char> &&
|
||||
std::is_same_v<PathChar, wchar_t>) {
|
||||
auto buf = basic_memory_buffer<wchar_t>();
|
||||
write_escaped_string<wchar_t>(std::back_inserter(buf), native);
|
||||
bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
|
||||
FMT_ASSERT(valid, "invalid utf16");
|
||||
} else if constexpr (std::is_same_v<Char, PathChar>) {
|
||||
write_escaped_string<std::filesystem::path::value_type>(
|
||||
std::back_inserter(quoted), native);
|
||||
} else {
|
||||
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Char> struct formatter<std::filesystem::path, Char> {
|
||||
private:
|
||||
format_specs<Char> specs_;
|
||||
detail::arg_ref<Char> width_ref_;
|
||||
bool debug_ = false;
|
||||
char path_type_ = 0;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
|
||||
|
||||
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
|
||||
auto it = ctx.begin(), end = ctx.end();
|
||||
if (it == end) return it;
|
||||
|
||||
it = detail::parse_align(it, end, specs_);
|
||||
if (it == end) return it;
|
||||
|
||||
it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
|
||||
if (it != end && *it == '?') {
|
||||
debug_ = true;
|
||||
++it;
|
||||
}
|
||||
if (it != end && (*it == 'g')) path_type_ = *it++;
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::filesystem::path& p, FormatContext& ctx) const {
|
||||
auto specs = specs_;
|
||||
# ifdef _WIN32
|
||||
auto path_string = !path_type_ ? p.native() : p.generic_wstring();
|
||||
# else
|
||||
auto path_string = !path_type_ ? p.native() : p.generic_string();
|
||||
# endif
|
||||
|
||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
|
||||
ctx);
|
||||
if (!debug_) {
|
||||
auto s = detail::get_path_string<Char>(p, path_string);
|
||||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
||||
}
|
||||
auto quoted = basic_memory_buffer<Char>();
|
||||
detail::write_escaped_path(quoted, p, path_string);
|
||||
return detail::write(ctx.out(),
|
||||
basic_string_view<Char>(quoted.data(), quoted.size()),
|
||||
specs);
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif // FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_EXPORT
|
||||
template <std::size_t N, typename Char>
|
||||
struct formatter<std::bitset<N>, Char> : nested_formatter<string_view> {
|
||||
private:
|
||||
// Functor because C++11 doesn't support generic lambdas.
|
||||
struct writer {
|
||||
const std::bitset<N>& bs;
|
||||
|
||||
template <typename OutputIt>
|
||||
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
|
||||
for (auto pos = N; pos > 0; --pos) {
|
||||
out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0'));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename FormatContext>
|
||||
auto format(const std::bitset<N>& bs, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return write_padded(ctx, writer{bs});
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Char>
|
||||
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::optional<T>, Char,
|
||||
std::enable_if_t<is_formattable<T, Char>::value>> {
|
||||
private:
|
||||
formatter<T, Char> underlying_;
|
||||
static constexpr basic_string_view<Char> optional =
|
||||
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
|
||||
'('>{};
|
||||
static constexpr basic_string_view<Char> none =
|
||||
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
|
||||
-> decltype(u.set_debug_format(set)) {
|
||||
u.set_debug_format(set);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
|
||||
|
||||
public:
|
||||
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
|
||||
maybe_set_debug_format(underlying_, true);
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::optional<T>& opt, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
if (!opt) return detail::write<Char>(ctx.out(), none);
|
||||
|
||||
auto out = ctx.out();
|
||||
out = detail::write<Char>(out, optional);
|
||||
ctx.advance_to(out);
|
||||
out = underlying_.format(*opt, ctx);
|
||||
return detail::write(out, ')');
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif // __cpp_lib_optional
|
||||
|
||||
#ifdef __cpp_lib_source_location
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_EXPORT
|
||||
template <> struct formatter<std::source_location> {
|
||||
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::source_location& loc, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
out = detail::write(out, loc.file_name());
|
||||
out = detail::write(out, ':');
|
||||
out = detail::write<char>(out, loc.line());
|
||||
out = detail::write(out, ':');
|
||||
out = detail::write<char>(out, loc.column());
|
||||
out = detail::write(out, ": ");
|
||||
out = detail::write(out, loc.function_name());
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
#if FMT_CPP_LIB_VARIANT
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using variant_index_sequence =
|
||||
std::make_index_sequence<std::variant_size<T>::value>;
|
||||
|
||||
template <typename> struct is_variant_like_ : std::false_type {};
|
||||
template <typename... Types>
|
||||
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
|
||||
|
||||
// formattable element check.
|
||||
template <typename T, typename C> class is_variant_formattable_ {
|
||||
template <std::size_t... Is>
|
||||
static std::conjunction<
|
||||
is_formattable<std::variant_alternative_t<Is, T>, C>...>
|
||||
check(std::index_sequence<Is...>);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
decltype(check(variant_index_sequence<T>{}))::value;
|
||||
};
|
||||
|
||||
template <typename Char, typename OutputIt, typename T>
|
||||
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
|
||||
if constexpr (is_string<T>::value)
|
||||
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||
else if constexpr (std::is_same_v<T, Char>)
|
||||
return write_escaped_char(out, v);
|
||||
else
|
||||
return write<Char>(out, v);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T> struct is_variant_like {
|
||||
static constexpr const bool value = detail::is_variant_like_<T>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename C> struct is_variant_formattable {
|
||||
static constexpr const bool value =
|
||||
detail::is_variant_formattable_<T, C>::value;
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Char> struct formatter<std::monostate, Char> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::monostate&, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return detail::write<Char>(ctx.out(), "monostate");
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename Variant, typename Char>
|
||||
struct formatter<
|
||||
Variant, Char,
|
||||
std::enable_if_t<std::conjunction_v<
|
||||
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const Variant& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
|
||||
out = detail::write<Char>(out, "variant(");
|
||||
FMT_TRY {
|
||||
std::visit(
|
||||
[&](const auto& v) {
|
||||
out = detail::write_variant_alternative<Char>(out, v);
|
||||
},
|
||||
value);
|
||||
}
|
||||
FMT_CATCH(const std::bad_variant_access&) {
|
||||
detail::write<Char>(out, "valueless by exception");
|
||||
}
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif // FMT_CPP_LIB_VARIANT
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_EXPORT
|
||||
template <typename Char> struct formatter<std::error_code, Char> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
out = detail::write_bytes(out, ec.category().name(), format_specs<Char>());
|
||||
out = detail::write<Char>(out, Char(':'));
|
||||
out = detail::write<Char>(out, ec.value());
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char>
|
||||
struct formatter<
|
||||
T, Char, // DEPRECATED! Mixing code unit types.
|
||||
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
|
||||
private:
|
||||
bool with_typename_ = false;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||
-> decltype(ctx.begin()) {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it == end || *it == '}') return it;
|
||||
if (*it == 't') {
|
||||
++it;
|
||||
with_typename_ = FMT_USE_TYPEID != 0;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename OutputIt>
|
||||
auto format(const std::exception& ex,
|
||||
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
|
||||
format_specs<Char> spec;
|
||||
auto out = ctx.out();
|
||||
if (!with_typename_)
|
||||
return detail::write_bytes(out, string_view(ex.what()), spec);
|
||||
|
||||
#if FMT_USE_TYPEID
|
||||
const std::type_info& ti = typeid(ex);
|
||||
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
|
||||
int status = 0;
|
||||
std::size_t size = 0;
|
||||
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
|
||||
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
|
||||
|
||||
string_view demangled_name_view;
|
||||
if (demangled_name_ptr) {
|
||||
demangled_name_view = demangled_name_ptr.get();
|
||||
|
||||
// Normalization of stdlib inline namespace names.
|
||||
// libc++ inline namespaces.
|
||||
// std::__1::* -> std::*
|
||||
// std::__1::__fs::* -> std::*
|
||||
// libstdc++ inline namespaces.
|
||||
// std::__cxx11::* -> std::*
|
||||
// std::filesystem::__cxx11::* -> std::filesystem::*
|
||||
if (demangled_name_view.starts_with("std::")) {
|
||||
char* begin = demangled_name_ptr.get();
|
||||
char* to = begin + 5; // std::
|
||||
for (char *from = to, *end = begin + demangled_name_view.size();
|
||||
from < end;) {
|
||||
// This is safe, because demangled_name is NUL-terminated.
|
||||
if (from[0] == '_' && from[1] == '_') {
|
||||
char* next = from + 1;
|
||||
while (next < end && *next != ':') next++;
|
||||
if (next[0] == ':' && next[1] == ':') {
|
||||
from = next + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*to++ = *from++;
|
||||
}
|
||||
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
|
||||
}
|
||||
} else {
|
||||
demangled_name_view = string_view(ti.name());
|
||||
}
|
||||
out = detail::write_bytes(out, demangled_name_view, spec);
|
||||
# elif FMT_MSC_VERSION
|
||||
string_view demangled_name_view(ti.name());
|
||||
if (demangled_name_view.starts_with("class "))
|
||||
demangled_name_view.remove_prefix(6);
|
||||
else if (demangled_name_view.starts_with("struct "))
|
||||
demangled_name_view.remove_prefix(7);
|
||||
out = detail::write_bytes(out, demangled_name_view, spec);
|
||||
# else
|
||||
out = detail::write_bytes(out, string_view(ti.name()), spec);
|
||||
# endif
|
||||
*out++ = ':';
|
||||
*out++ = ' ';
|
||||
return detail::write_bytes(out, string_view(ex.what()), spec);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_flip : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T> struct is_bit_reference_like {
|
||||
static constexpr const bool value =
|
||||
std::is_convertible<T, bool>::value &&
|
||||
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
|
||||
};
|
||||
|
||||
#ifdef _LIBCPP_VERSION
|
||||
|
||||
// Workaround for libc++ incompatibility with C++ standard.
|
||||
// According to the Standard, `bitset::operator[] const` returns bool.
|
||||
template <typename C>
|
||||
struct is_bit_reference_like<std::__bit_const_reference<C>> {
|
||||
static constexpr const bool value = true;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// We can't use std::vector<bool, Allocator>::reference and
|
||||
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
|
||||
// in partial specialization.
|
||||
FMT_EXPORT
|
||||
template <typename BitRef, typename Char>
|
||||
struct formatter<BitRef, Char,
|
||||
enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
|
||||
: formatter<bool, Char> {
|
||||
template <typename FormatContext>
|
||||
FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<bool, Char>::format(v, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::atomic<T>, Char,
|
||||
enable_if_t<is_formattable<T, Char>::value>>
|
||||
: formatter<T, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const std::atomic<T>& v, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<T, Char>::format(v.load(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __cpp_lib_atomic_flag_test
|
||||
FMT_EXPORT
|
||||
template <typename Char>
|
||||
struct formatter<std::atomic_flag, Char> : formatter<bool, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const std::atomic_flag& v, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<bool, Char>::format(v.test(), ctx);
|
||||
}
|
||||
};
|
||||
#endif // __cpp_lib_atomic_flag_test
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
#endif // FMT_STD_H_
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
add_files(
|
||||
scriptrun.cpp
|
||||
scriptrun.h
|
||||
CONDITION ICU_i18n_FOUND
|
||||
)
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
|
||||
|
||||
See Terms of Use <https://www.unicode.org/copyright.html>
|
||||
for definitions of Unicode Inc.’s Data Files and Software.
|
||||
|
||||
NOTICE TO USER: Carefully read the following legal agreement.
|
||||
BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
|
||||
DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
|
||||
YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
|
||||
TERMS AND CONDITIONS OF THIS AGREEMENT.
|
||||
IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
|
||||
THE DATA FILES OR SOFTWARE.
|
||||
|
||||
COPYRIGHT AND PERMISSION NOTICE
|
||||
|
||||
Copyright © 1991-2023 Unicode, Inc. All rights reserved.
|
||||
Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Unicode data files and any associated documentation
|
||||
(the "Data Files") or Unicode software and any associated documentation
|
||||
(the "Software") to deal in the Data Files or Software
|
||||
without restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
the Data Files or Software, and to permit persons to whom the Data Files
|
||||
or Software are furnished to do so, provided that either
|
||||
(a) this copyright and permission notice appear with all copies
|
||||
of the Data Files or Software, or
|
||||
(b) this copyright and permission notice appear in associated
|
||||
Documentation.
|
||||
|
||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in these Data Files or Software without prior
|
||||
written authorization of the copyright holder.
|
||||
Vendored
+208
@@ -0,0 +1,208 @@
|
||||
// © 2016 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html
|
||||
/*
|
||||
*******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2016, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
*
|
||||
*******************************************************************************
|
||||
* file name: scrptrun.cpp
|
||||
*
|
||||
* created on: 10/17/2001
|
||||
* created by: Eric R. Mader
|
||||
*/
|
||||
|
||||
#include <unicode/utypes.h>
|
||||
#include <unicode/uscript.h>
|
||||
|
||||
#include "scriptrun.h"
|
||||
|
||||
// Copied from cmemory.h
|
||||
#define UPRV_LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
const char ScriptRun::fgClassID=0;
|
||||
|
||||
UChar32 ScriptRun::pairedChars[] = {
|
||||
0x0028, 0x0029, // ascii paired punctuation
|
||||
0x003c, 0x003e,
|
||||
0x005b, 0x005d,
|
||||
0x007b, 0x007d,
|
||||
0x00ab, 0x00bb, // guillemets
|
||||
0x2018, 0x2019, // general punctuation
|
||||
0x201c, 0x201d,
|
||||
0x2039, 0x203a,
|
||||
0x3008, 0x3009, // chinese paired punctuation
|
||||
0x300a, 0x300b,
|
||||
0x300c, 0x300d,
|
||||
0x300e, 0x300f,
|
||||
0x3010, 0x3011,
|
||||
0x3014, 0x3015,
|
||||
0x3016, 0x3017,
|
||||
0x3018, 0x3019,
|
||||
0x301a, 0x301b
|
||||
};
|
||||
|
||||
const int32_t ScriptRun::pairedCharCount = UPRV_LENGTHOF(pairedChars);
|
||||
const int32_t ScriptRun::pairedCharPower = 1 << highBit(pairedCharCount);
|
||||
const int32_t ScriptRun::pairedCharExtra = pairedCharCount - pairedCharPower;
|
||||
|
||||
int8_t ScriptRun::highBit(int32_t value)
|
||||
{
|
||||
if (value <= 0) {
|
||||
return -32;
|
||||
}
|
||||
|
||||
int8_t bit = 0;
|
||||
|
||||
if (value >= 1 << 16) {
|
||||
value >>= 16;
|
||||
bit += 16;
|
||||
}
|
||||
|
||||
if (value >= 1 << 8) {
|
||||
value >>= 8;
|
||||
bit += 8;
|
||||
}
|
||||
|
||||
if (value >= 1 << 4) {
|
||||
value >>= 4;
|
||||
bit += 4;
|
||||
}
|
||||
|
||||
if (value >= 1 << 2) {
|
||||
value >>= 2;
|
||||
bit += 2;
|
||||
}
|
||||
|
||||
if (value >= 1 << 1) {
|
||||
value >>= 1;
|
||||
bit += 1;
|
||||
}
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
int32_t ScriptRun::getPairIndex(UChar32 ch)
|
||||
{
|
||||
int32_t probe = pairedCharPower;
|
||||
int32_t index = 0;
|
||||
|
||||
if (ch >= pairedChars[pairedCharExtra]) {
|
||||
index = pairedCharExtra;
|
||||
}
|
||||
|
||||
while (probe > (1 << 0)) {
|
||||
probe >>= 1;
|
||||
|
||||
if (ch >= pairedChars[index + probe]) {
|
||||
index += probe;
|
||||
}
|
||||
}
|
||||
|
||||
if (pairedChars[index] != ch) {
|
||||
index = -1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
UBool ScriptRun::sameScript(int32_t scriptOne, int32_t scriptTwo)
|
||||
{
|
||||
return scriptOne <= USCRIPT_INHERITED || scriptTwo <= USCRIPT_INHERITED || scriptOne == scriptTwo;
|
||||
}
|
||||
|
||||
UBool ScriptRun::next()
|
||||
{
|
||||
int32_t startSP = parenSP; // used to find the first new open character
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
|
||||
// if we've fallen off the end of the text, we're done
|
||||
if (scriptEnd >= charLimit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
scriptCode = USCRIPT_COMMON;
|
||||
|
||||
for (scriptStart = scriptEnd; scriptEnd < charLimit; scriptEnd += 1) {
|
||||
char16_t high = charArray[scriptEnd];
|
||||
UChar32 ch = high;
|
||||
|
||||
// if the character is a high surrogate and it's not the last one
|
||||
// in the text, see if it's followed by a low surrogate
|
||||
if (high >= 0xD800 && high <= 0xDBFF && scriptEnd < charLimit - 1)
|
||||
{
|
||||
char16_t low = charArray[scriptEnd + 1];
|
||||
|
||||
// if it is followed by a low surrogate,
|
||||
// consume it and form the full character
|
||||
if (low >= 0xDC00 && low <= 0xDFFF) {
|
||||
ch = (high - 0xD800) * 0x0400 + low - 0xDC00 + 0x10000;
|
||||
scriptEnd += 1;
|
||||
}
|
||||
}
|
||||
|
||||
UScriptCode sc = uscript_getScript(ch, &error);
|
||||
int32_t pairIndex = getPairIndex(ch);
|
||||
|
||||
// Paired character handling:
|
||||
//
|
||||
// if it's an open character, push it onto the stack.
|
||||
// if it's a close character, find the matching open on the
|
||||
// stack, and use that script code. Any non-matching open
|
||||
// characters above it on the stack will be poped.
|
||||
if (pairIndex >= 0) {
|
||||
if ((pairIndex & 1) == 0) {
|
||||
parenStack[++parenSP].pairIndex = pairIndex;
|
||||
parenStack[parenSP].scriptCode = scriptCode;
|
||||
} else if (parenSP >= 0) {
|
||||
int32_t pi = pairIndex & ~1;
|
||||
|
||||
while (parenSP >= 0 && parenStack[parenSP].pairIndex != pi) {
|
||||
parenSP -= 1;
|
||||
}
|
||||
|
||||
if (parenSP < startSP) {
|
||||
startSP = parenSP;
|
||||
}
|
||||
|
||||
if (parenSP >= 0) {
|
||||
sc = parenStack[parenSP].scriptCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sameScript(scriptCode, sc)) {
|
||||
if (scriptCode <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) {
|
||||
scriptCode = sc;
|
||||
|
||||
// now that we have a final script code, fix any open
|
||||
// characters we pushed before we knew the script code.
|
||||
while (startSP < parenSP) {
|
||||
parenStack[++startSP].scriptCode = scriptCode;
|
||||
}
|
||||
}
|
||||
|
||||
// if this character is a close paired character,
|
||||
// pop it from the stack
|
||||
if (pairIndex >= 0 && (pairIndex & 1) != 0 && parenSP >= 0) {
|
||||
parenSP -= 1;
|
||||
startSP -= 1;
|
||||
}
|
||||
} else {
|
||||
// if the run broke on a surrogate pair,
|
||||
// end it before the high surrogate
|
||||
if (ch >= 0x10000) {
|
||||
scriptEnd -= 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
Vendored
+159
@@ -0,0 +1,159 @@
|
||||
// © 2016 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html
|
||||
/*
|
||||
*******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2003, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
*
|
||||
*******************************************************************************
|
||||
* file name: scrptrun.h
|
||||
*
|
||||
* created on: 10/17/2001
|
||||
* created by: Eric R. Mader
|
||||
*/
|
||||
|
||||
#ifndef __SCRPTRUN_H
|
||||
#define __SCRPTRUN_H
|
||||
|
||||
#include <unicode/utypes.h>
|
||||
#include <unicode/uobject.h>
|
||||
#include <unicode/uscript.h>
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
struct ScriptRecord
|
||||
{
|
||||
UChar32 startChar;
|
||||
UChar32 endChar;
|
||||
UScriptCode scriptCode;
|
||||
};
|
||||
|
||||
struct ParenStackEntry
|
||||
{
|
||||
int32_t pairIndex;
|
||||
UScriptCode scriptCode;
|
||||
};
|
||||
|
||||
class ScriptRun : public UObject {
|
||||
public:
|
||||
ScriptRun();
|
||||
|
||||
ScriptRun(const char16_t *chars, int32_t length);
|
||||
|
||||
ScriptRun(const char16_t *chars, int32_t start, int32_t length);
|
||||
|
||||
void reset();
|
||||
|
||||
void reset(int32_t start, int32_t count);
|
||||
|
||||
void reset(const char16_t *chars, int32_t start, int32_t length);
|
||||
|
||||
int32_t getScriptStart();
|
||||
|
||||
int32_t getScriptEnd();
|
||||
|
||||
UScriptCode getScriptCode();
|
||||
|
||||
UBool next();
|
||||
|
||||
/**
|
||||
* ICU "poor man's RTTI", returns a UClassID for the actual class.
|
||||
*
|
||||
* @stable ICU 2.2
|
||||
*/
|
||||
virtual inline UClassID getDynamicClassID() const override { return getStaticClassID(); }
|
||||
|
||||
/**
|
||||
* ICU "poor man's RTTI", returns a UClassID for this class.
|
||||
*
|
||||
* @stable ICU 2.2
|
||||
*/
|
||||
static inline UClassID getStaticClassID() { return (UClassID)const_cast<char *>(&fgClassID); }
|
||||
|
||||
private:
|
||||
|
||||
static UBool sameScript(int32_t scriptOne, int32_t scriptTwo);
|
||||
|
||||
int32_t charStart;
|
||||
int32_t charLimit;
|
||||
const char16_t *charArray;
|
||||
|
||||
int32_t scriptStart;
|
||||
int32_t scriptEnd;
|
||||
UScriptCode scriptCode;
|
||||
|
||||
ParenStackEntry parenStack[128];
|
||||
int32_t parenSP;
|
||||
|
||||
static int8_t highBit(int32_t value);
|
||||
static int32_t getPairIndex(UChar32 ch);
|
||||
|
||||
static UChar32 pairedChars[];
|
||||
static const int32_t pairedCharCount;
|
||||
static const int32_t pairedCharPower;
|
||||
static const int32_t pairedCharExtra;
|
||||
|
||||
/**
|
||||
* The address of this static class variable serves as this class's ID
|
||||
* for ICU "poor man's RTTI".
|
||||
*/
|
||||
static const char fgClassID;
|
||||
};
|
||||
|
||||
inline ScriptRun::ScriptRun()
|
||||
{
|
||||
reset(nullptr, 0, 0);
|
||||
}
|
||||
|
||||
inline ScriptRun::ScriptRun(const char16_t *chars, int32_t length)
|
||||
{
|
||||
reset(chars, 0, length);
|
||||
}
|
||||
|
||||
inline ScriptRun::ScriptRun(const char16_t *chars, int32_t start, int32_t length)
|
||||
{
|
||||
reset(chars, start, length);
|
||||
}
|
||||
|
||||
inline int32_t ScriptRun::getScriptStart()
|
||||
{
|
||||
return scriptStart;
|
||||
}
|
||||
|
||||
inline int32_t ScriptRun::getScriptEnd()
|
||||
{
|
||||
return scriptEnd;
|
||||
}
|
||||
|
||||
inline UScriptCode ScriptRun::getScriptCode()
|
||||
{
|
||||
return scriptCode;
|
||||
}
|
||||
|
||||
inline void ScriptRun::reset()
|
||||
{
|
||||
scriptStart = charStart;
|
||||
scriptEnd = charStart;
|
||||
scriptCode = USCRIPT_INVALID_CODE;
|
||||
parenSP = -1;
|
||||
}
|
||||
|
||||
inline void ScriptRun::reset(int32_t start, int32_t length)
|
||||
{
|
||||
charStart = start;
|
||||
charLimit = start + length;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
inline void ScriptRun::reset(const char16_t *chars, int32_t start, int32_t length)
|
||||
{
|
||||
charArray = chars;
|
||||
|
||||
reset(start, length);
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
Vendored
+29
-29
@@ -60,7 +60,7 @@
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
#define T_MASK ((uint32)~0)
|
||||
#define T_MASK ((uint32_t)~0)
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 0x242070db
|
||||
@@ -126,33 +126,33 @@
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
static inline void Md5Set1(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti)
|
||||
static inline void Md5Set1(const uint32_t *X, uint32_t *a, const uint32_t *b, const uint32_t *c, const uint32_t *d, const uint8_t k, const uint8_t s, const uint32_t Ti)
|
||||
{
|
||||
uint32 t = (*b & *c) | (~*b & *d);
|
||||
uint32_t t = (*b & *c) | (~*b & *d);
|
||||
t += *a + X[k] + Ti;
|
||||
*a = ROL(t, s) + *b;
|
||||
*a = std::rotl(t, s) + *b;
|
||||
}
|
||||
|
||||
static inline void Md5Set2(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti)
|
||||
static inline void Md5Set2(const uint32_t *X, uint32_t *a, const uint32_t *b, const uint32_t *c, const uint32_t *d, const uint8_t k, const uint8_t s, const uint32_t Ti)
|
||||
{
|
||||
uint32 t = (*b & *d) | (*c & ~*d);
|
||||
uint32_t t = (*b & *d) | (*c & ~*d);
|
||||
t += *a + X[k] + Ti;
|
||||
*a = ROL(t, s) + *b;
|
||||
*a = std::rotl(t, s) + *b;
|
||||
}
|
||||
|
||||
|
||||
static inline void Md5Set3(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti)
|
||||
static inline void Md5Set3(const uint32_t *X, uint32_t *a, const uint32_t *b, const uint32_t *c, const uint32_t *d, const uint8_t k, const uint8_t s, const uint32_t Ti)
|
||||
{
|
||||
uint32 t = *b ^ *c ^ *d;
|
||||
uint32_t t = *b ^ *c ^ *d;
|
||||
t += *a + X[k] + Ti;
|
||||
*a = ROL(t, s) + *b;
|
||||
*a = std::rotl(t, s) + *b;
|
||||
}
|
||||
|
||||
static inline void Md5Set4(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti)
|
||||
static inline void Md5Set4(const uint32_t *X, uint32_t *a, const uint32_t *b, const uint32_t *c, const uint32_t *d, const uint8_t k, const uint8_t s, const uint32_t Ti)
|
||||
{
|
||||
uint32 t = *c ^ (*b | ~*d);
|
||||
uint32_t t = *c ^ (*b | ~*d);
|
||||
t += *a + X[k] + Ti;
|
||||
*a = ROL(t, s) + *b;
|
||||
*a = std::rotl(t, s) + *b;
|
||||
}
|
||||
|
||||
Md5::Md5()
|
||||
@@ -165,17 +165,17 @@ Md5::Md5()
|
||||
abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void Md5::Process(const uint8 *data /*[64]*/)
|
||||
void Md5::Process(const uint8_t *data /*[64]*/)
|
||||
{
|
||||
uint32 a = this->abcd[0];
|
||||
uint32 b = this->abcd[1];
|
||||
uint32 c = this->abcd[2];
|
||||
uint32 d = this->abcd[3];
|
||||
uint32_t a = this->abcd[0];
|
||||
uint32_t b = this->abcd[1];
|
||||
uint32_t c = this->abcd[2];
|
||||
uint32_t d = this->abcd[3];
|
||||
|
||||
uint32 X[16];
|
||||
uint32_t X[16];
|
||||
|
||||
/* Convert the uint8 data to uint32 LE */
|
||||
const uint32 *px = (const uint32 *)data;
|
||||
/* Convert the uint8_t data to uint32_t LE */
|
||||
const uint32_t *px = (const uint32_t *)data;
|
||||
for (uint i = 0; i < 16; i++) {
|
||||
X[i] = TO_LE32(*px);
|
||||
px++;
|
||||
@@ -264,15 +264,15 @@ void Md5::Process(const uint8 *data /*[64]*/)
|
||||
|
||||
void Md5::Append(const void *data, const size_t nbytes)
|
||||
{
|
||||
const uint8 *p = (const uint8 *)data;
|
||||
const uint8_t *p = (const uint8_t *)data;
|
||||
size_t left = nbytes;
|
||||
const size_t offset = (this->count[0] >> 3) & 63;
|
||||
const uint32 nbits = (uint32)(nbytes << 3);
|
||||
const uint32_t nbits = (uint32_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0) return;
|
||||
|
||||
/* Update the message length. */
|
||||
this->count[1] += (uint32)(nbytes >> 29);
|
||||
this->count[1] += (uint32_t)(nbytes >> 29);
|
||||
this->count[0] += nbits;
|
||||
|
||||
if (this->count[0] < nbits) this->count[1]++;
|
||||
@@ -297,19 +297,19 @@ void Md5::Append(const void *data, const size_t nbytes)
|
||||
if (left) memcpy(this->buf, p, left);
|
||||
}
|
||||
|
||||
void Md5::Finish(uint8 digest[16])
|
||||
void Md5::Finish(MD5Hash &digest)
|
||||
{
|
||||
static const uint8 pad[64] = {
|
||||
static const uint8_t pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
uint8 data[8];
|
||||
uint8_t data[8];
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (uint i = 0; i < 8; ++i) {
|
||||
data[i] = (uint8)(this->count[i >> 2] >> ((i & 3) << 3));
|
||||
data[i] = (uint8_t)(this->count[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
@@ -318,6 +318,6 @@ void Md5::Finish(uint8 digest[16])
|
||||
this->Append(data, 8);
|
||||
|
||||
for (uint i = 0; i < 16; ++i) {
|
||||
digest[i] = (uint8)(this->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
digest[i] = (uint8_t)(this->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+24
-5
@@ -53,18 +53,37 @@
|
||||
#ifndef MD5_INCLUDED
|
||||
#define MD5_INCLUDED
|
||||
|
||||
/** The number of bytes in a MD5 hash. */
|
||||
static const size_t MD5_HASH_BYTES = 16;
|
||||
|
||||
/** Container for storing a MD5 hash/checksum/digest. */
|
||||
struct MD5Hash : std::array<byte, MD5_HASH_BYTES> {
|
||||
MD5Hash() : std::array<byte, MD5_HASH_BYTES>{} {}
|
||||
|
||||
/**
|
||||
* Exclusively-or the given hash into this hash.
|
||||
* @param other The other hash.
|
||||
* @return Reference to this hash.
|
||||
*/
|
||||
MD5Hash &operator^=(const MD5Hash &other)
|
||||
{
|
||||
for (size_t i = 0; i < size(); i++) this->operator[](i) ^= other[i];
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct Md5 {
|
||||
private:
|
||||
uint32 count[2]; ///< message length in bits, lsw first
|
||||
uint32 abcd[4]; ///< digest buffer
|
||||
uint8 buf[64]; ///< accumulate block
|
||||
uint32_t count[2]; ///< message length in bits, lsw first
|
||||
uint32_t abcd[4]; ///< digest buffer
|
||||
uint8_t buf[64]; ///< accumulate block
|
||||
|
||||
void Process(const uint8 *data);
|
||||
void Process(const uint8_t *data);
|
||||
|
||||
public:
|
||||
Md5();
|
||||
void Append(const void *data, const size_t nbytes);
|
||||
void Finish(uint8 digest[16]);
|
||||
void Finish(MD5Hash &digest);
|
||||
};
|
||||
|
||||
#endif /* MD5_INCLUDED */
|
||||
|
||||
Vendored
+63
@@ -0,0 +1,63 @@
|
||||
Designers
|
||||
---------
|
||||
|
||||
- **ChaCha20:** Daniel J. Bernstein.
|
||||
- **Poly1305:** Daniel J. Bernstein.
|
||||
- **BLAKE2:** Jean-Philippe Aumasson, Christian Winnerlein, Samuel Neves,
|
||||
and Zooko Wilcox-O'Hearn.
|
||||
- **Argon2:** Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich.
|
||||
- **X25519:** Daniel J. Bernstein.
|
||||
- **EdDSA:** Daniel J. Bernstein, Bo-Yin Yang, Niels Duif, Peter
|
||||
Schwabe, and Tanja Lange.
|
||||
|
||||
Implementors
|
||||
------------
|
||||
|
||||
- **ChaCha20:** Loup Vaillant, implemented from spec.
|
||||
- **Poly1305:** Loup Vaillant, implemented from spec.
|
||||
- **BLAKE2b:** Loup Vaillant, implemented from spec.
|
||||
- **Argon2i:** Loup Vaillant, implemented from spec.
|
||||
- **X25519:** Daniel J. Bernstein, taken and packaged from SUPERCOP
|
||||
ref10.
|
||||
- **EdDSA:** Loup Vaillant, with bits and pieces from SUPERCOP ref10.
|
||||
|
||||
Test suite
|
||||
----------
|
||||
|
||||
Designed and implemented by Loup Vaillant, using _libsodium_ (by many
|
||||
authors), and _ed25519-donna_ (by Andrew Moon —floodyberry).
|
||||
|
||||
Manual
|
||||
------
|
||||
|
||||
Loup Vaillant, Fabio Scotoni, and Michael Savage.
|
||||
|
||||
- Loup Vaillant did a first draft.
|
||||
- Fabio Scotoni rewrote the manual into proper man pages (and
|
||||
substantially changed it in the process).
|
||||
- Michael Savage did extensive editing and proofreading.
|
||||
|
||||
Thanks
|
||||
------
|
||||
|
||||
Fabio Scotoni provided much needed advice about testing, interface,
|
||||
packaging, and the general direction of the whole project. He also
|
||||
redesigned the monocypher.org style sheets.
|
||||
|
||||
Mike Pechkin and André Maroneze found bugs in earlier versions of
|
||||
Monocypher.
|
||||
|
||||
Andrew Moon clarified carry propagation in modular arithmetic, and
|
||||
provided advice and code that significantly simplified and improved
|
||||
Elligator2 mappings.
|
||||
|
||||
Mike Hamburg explained comb algorithms, including the signed
|
||||
all-bits-set comb described in his 2012 paper, Fast and compact
|
||||
elliptic-curve cryptography. This made EdDSA signatures over twice as
|
||||
fast.
|
||||
|
||||
Samuel Lucas found many typos in both the manual and the website.
|
||||
|
||||
Jens Alfke added some #ifdefs that enabled Monocypher to compile into
|
||||
a C++ namespace, preventing symbol collisions with similarly-named
|
||||
functions in other crypto libraries.
|
||||
Vendored
+295
@@ -0,0 +1,295 @@
|
||||
4.0.2
|
||||
-----
|
||||
2023/08/24
|
||||
|
||||
- Fixed multiple-lanes Argon2.
|
||||
- Improved Poly1305 performance.
|
||||
- Improved Argon2 performance.
|
||||
- Makefiles no longer override standard environment variables.
|
||||
|
||||
|
||||
4.0.1
|
||||
-----
|
||||
2023/03/06
|
||||
|
||||
- Fixed Ed25519 secret key size in function prototype.
|
||||
- Fixed soname (should have been changed in 4.0.0)
|
||||
- Added convenience sub-targets to makefile.
|
||||
- Briefly specified wire format of Elligator and incremental AEAD.
|
||||
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
2023/02/20
|
||||
|
||||
- Fixed unsafe signature API.
|
||||
- Simpler, more flexible low-level signature API.
|
||||
- Fully specified, consensus-friendly signatures.
|
||||
- Added Argon2d and Argon2id, support multiple lanes.
|
||||
- Added safe and fast streaming AEAD.
|
||||
- Added HKDF-SHA-512 and documented BLAKE2b KDF.
|
||||
- More consistent and memorable function names.
|
||||
- POSIX makefile.
|
||||
|
||||
|
||||
3.1.3
|
||||
-----
|
||||
2022/04/25
|
||||
|
||||
- Fixed many typos in the documentation.
|
||||
- Fixed buffer overflow in speed benchmarks.
|
||||
- Fixed some MSVC warnings.
|
||||
- Fixed a minor violation of the Elligator2 reverse map specs.
|
||||
- Added `change-prefix.sh` to help changing the `crypto_` prefix.
|
||||
- Added the `MONOCYPHER_CPP_NAMESPACE` preprocessor definition to
|
||||
support namespaces for C++.
|
||||
- Deprecated `crypto_key_exchange()`
|
||||
- Use GitHub actions to automate the regular test suite.
|
||||
|
||||
|
||||
3.1.2
|
||||
-----
|
||||
2020/12/27
|
||||
|
||||
- Addressed issues from Cure53's audit:
|
||||
- MON-01-001: Clarified which CSPRNG to use on Darwin.
|
||||
- MON-01-002: Won't fix (nonce handling is a core design decision).
|
||||
- MON-01-004: Compared with Kleshni's implementation.
|
||||
- MON-01-005: Split a dedicated "advanced" folder in the manual.
|
||||
- Quality assurance for 2^255-19 arithmetic (elliptic curves):
|
||||
- Documented carry propagation.
|
||||
- Enforced slightly safer invariants.
|
||||
- Improved the speed of EdDSA signature generation.
|
||||
- Made the vectors.h header more compact and easier to modify.
|
||||
- TIS-CI integration.
|
||||
- Added speed benchmark for ed25519-donna.
|
||||
- Documented lengths limits of `crypto_ietf_chacha20()`
|
||||
|
||||
|
||||
3.1.1
|
||||
-----
|
||||
2020/06/15
|
||||
|
||||
- Various documentation fixes.
|
||||
- Fixed various compiler warnings.
|
||||
- Fixed some integer overflows (16-bit platforms only).
|
||||
|
||||
|
||||
3.1.0
|
||||
-----
|
||||
2020/04/03
|
||||
|
||||
- Added Elligator 2 mappings (hash to curve, curve to hash).
|
||||
- Added OPRF support (with scalar inversion).
|
||||
- Added Edwards25519 -> Curve25519 conversions.
|
||||
|
||||
|
||||
3.0.0
|
||||
-----
|
||||
2020/01/19
|
||||
|
||||
- Deprecated the incremental AEAD interface.
|
||||
- Deprecated the incremental Chacha20, added a direct interface.
|
||||
- Added IETF Chacha20 (96-bit nonce), as described in RFC 8439.
|
||||
- Moved deprecated interfaces to a separate `src/deprecated` folder.
|
||||
- Removed the `ED25519_SHA512` preprocessor flag.
|
||||
- `crypto_x25519()` and `crypto_key_exchange()` now return `void`.
|
||||
- Added a custom hash interface to EdDSA. Several instances of EdDSA
|
||||
can share the same binary.
|
||||
- Added optional support for HMAC SHA-512.
|
||||
- Moved SHA-512 operations to `src/optional/monocypher-ed25519.(h|c)`.
|
||||
- Optional support for Ed25519 no longer requires a preprocessor flag.
|
||||
Add `src/optional/monocypher-ed25519.(h|c)` to your project instead.
|
||||
|
||||
|
||||
2.0.6
|
||||
-----
|
||||
2019/10/21
|
||||
|
||||
- Added the `BLAKE2_NO_UNROLLING` preprocessor definition. Activating
|
||||
it makes the binary about 5KB smaller and speeds up processing times
|
||||
on many embedded processors.
|
||||
- Reduced the stack usage of signature verification by about
|
||||
40%. Signature verification now fits in smaller machines.
|
||||
- Fixed many implicit casts warnings.
|
||||
- Fixed the manual here and there.
|
||||
- Lots of small nitpicks.
|
||||
|
||||
|
||||
2.0.5
|
||||
-----
|
||||
2018/08/23
|
||||
|
||||
- Faster EdDSA signatures and verification. Like, 4 times as fast.
|
||||
|
||||
|
||||
2.0.4
|
||||
-----
|
||||
2018/06/24
|
||||
|
||||
- Corrected a critical vulnerability found by Mike Pechkin in EdDSA,
|
||||
where crypto_check() was accepting invalid signatures. The current
|
||||
fix removes a buggy optimisation, effectively halving the performance
|
||||
of EdDSA.
|
||||
- The test suite no longer tries to allocate zero bytes (some platforms
|
||||
fail such an allocation).
|
||||
|
||||
2.0.3
|
||||
-----
|
||||
2018/06/16
|
||||
|
||||
- Corrected undefined behaviour in BLAKE2b.
|
||||
- Improved the test suite (faster, better coverage).
|
||||
|
||||
2.0.2
|
||||
-----
|
||||
2018/04/23
|
||||
|
||||
- Corrected a couple failures to wipe secret buffers.
|
||||
- Corrected a bug that prevented compilation in Ed25519 mode.
|
||||
- Adjusted the number of test vectors in the test suite.
|
||||
- Improved tests for incremental interfaces.
|
||||
- Replaced the GNU all permissive licence by a public domain dedication
|
||||
(Creative Commons CC-0). The BSD licence remains as a fallback.
|
||||
|
||||
2.0.1
|
||||
-----
|
||||
2018/03/07
|
||||
|
||||
- Followed a systematic pattern for the loading code of symmetric
|
||||
crypto. It is now easier to review.
|
||||
- Tweaked Poly1305 code to make it easier to prove correct.
|
||||
|
||||
2.0.0
|
||||
-----
|
||||
2018/02/14
|
||||
|
||||
- Changed the authenticated encryption format. It now conforms to
|
||||
RFC 7539, with one exception: it uses XChacha20 initialisation instead
|
||||
of the IETF version of Chacha20. This new format conforms to
|
||||
libsodium's `crypto_aead_xchacha20poly1305_ietf_encrypt`.
|
||||
- Removed `crypto_lock_encrypt()` and `crypto_lock_auth()`.
|
||||
- Renamed `crypto_lock_aead_auth()` to `crypto_lock_auth_ad()`.
|
||||
- Renamed `crypto_unlock_aead_auth()` to `crypto_unlock_auth_ad()`.
|
||||
- Added `crypto_lock_auth_message()` and `crypto_unlock_auth_message()`.
|
||||
- Renamed `crypto_aead_lock` to `crypto_lock_aead`.
|
||||
- Renamed `crypto_aead_unlock` to `crypto_unlock_aead`.
|
||||
|
||||
The format change facilitates optimisation by aligning data to block
|
||||
boundaries. The API changes increase consistency.
|
||||
|
||||
1.1.0
|
||||
-----
|
||||
2018/02/06
|
||||
|
||||
- Rewrote the manual into proper man pages.
|
||||
- Added incremental interfaces for authenticated encryption and
|
||||
signatures.
|
||||
- Replaced `crypto_memcmp()` by 3 fixed size buffer comparisons (16, 32,
|
||||
and 64 bytes), to make sure the generated code remains constant time.
|
||||
- A couple breaking API changes, easily fixed by renaming the affected
|
||||
functions.
|
||||
|
||||
1.0.1
|
||||
-----
|
||||
2017/07/23
|
||||
|
||||
- Optimised the loading and unloading code of the symmetric crypto
|
||||
(BLAKE2b, SHA-512, Chacha20, and Poly1305).
|
||||
- Fused self-contained tests together for easier analysis with Frama-C
|
||||
and the TIS interpreter.
|
||||
|
||||
1.0
|
||||
---
|
||||
2017/07/18
|
||||
|
||||
- Renamed `crypto_chacha20_Xinit` to `crypto_chacha20_x_init`, for
|
||||
consistency reasons (snake case everywhere).
|
||||
- Fixed signed integer overflow detected by UBSan.
|
||||
- Doubled the speed of EdDSA by performing the scalar product in
|
||||
Montgomery space.
|
||||
|
||||
0.8
|
||||
---
|
||||
2017/07/06
|
||||
|
||||
- Added about a hundred lines of code to improve performance of public
|
||||
key cryptography. Diffie-Hellman is now 20% faster than before.
|
||||
The effects are less pronounced for EdDSA.
|
||||
- Added random self-consistency tests.
|
||||
- Added a speed benchmark against libsodium.
|
||||
|
||||
0.7
|
||||
---
|
||||
2017/06/07
|
||||
|
||||
- Slightly changed the authenticated encryption API. Functions are
|
||||
now all in "detached" mode. The reason is better support for
|
||||
authenticated encryption _without_ additional data.
|
||||
- Rewrote BLAKE2b from spec so it can use the same licence as
|
||||
everything else.
|
||||
- Added random tests that compare Monocypher with libsodium and
|
||||
ed25519-donna.
|
||||
- Added explicit support for Frama-C analysis (this doesn't affect the
|
||||
source code).
|
||||
|
||||
0.6
|
||||
---
|
||||
2017/03/17
|
||||
|
||||
- Fixed incorrect Poly1305 output on empty messages. (Found by Mike
|
||||
Pechkin.)
|
||||
|
||||
0.5
|
||||
---
|
||||
2017/03/10
|
||||
|
||||
- Fixed many undefined behaviours in Curve25519 that occur whenever
|
||||
we perform a left shift on a signed negative integer. It doesn't
|
||||
affect the generated code, but you never know. (Found with Frama-C
|
||||
by André Maroneze.)
|
||||
|
||||
Fun fact: TweetNaCl and ref10 have the same bug. Libsodium has
|
||||
corrected the issue, though.
|
||||
|
||||
For those who don't comprehend the magnitude of this madness, the
|
||||
expression `-1 << 3` is undefined in C. This is explained in
|
||||
section 6.5.7(§4) of the C11 standard.
|
||||
|
||||
0.4
|
||||
---
|
||||
2017/03/09
|
||||
|
||||
- Fixed critical bug causing Argon2i to fail whenever it uses more
|
||||
than 512 blocks. It was reading uninitialised memory and the
|
||||
results were incorrect. (Found by Mike Pechkin.)
|
||||
- Fixed an undefined behaviour in Curve25519 (`fe_tobytes()`). It was
|
||||
accessing uninitialised memory before throwing it away. It didn't
|
||||
affect the compiled code nor the results, but you never know.
|
||||
(Found with [Frama-C](http://frama-c.com) by André Maroneze.)
|
||||
|
||||
0.3
|
||||
---
|
||||
2017/02/27
|
||||
|
||||
- Got the invariants of Poly1305 right and put them in the comments.
|
||||
There was no bug, but that was lucky (turned out the IETF test
|
||||
vectors were designed to trigger the bugs I was afraid of).
|
||||
- Simplified Poly1305 finalisation (replaced conditional subtraction
|
||||
by a carry propagation).
|
||||
- Made a few cosmetic changes here and there.
|
||||
|
||||
0.2
|
||||
---
|
||||
????/??/??
|
||||
|
||||
- Public interface significantly reworked. Removed redundant, hard to
|
||||
mess up constructions.
|
||||
- Added AEAD.
|
||||
- Sped up Curve25519 by a factor of more than 6 (switched to ref10
|
||||
arithmetic).
|
||||
- Added various test vectors and completed the consistency tests.
|
||||
|
||||
0.1
|
||||
---
|
||||
2016/??/??
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
add_files(
|
||||
monocypher-ed25519.cpp
|
||||
monocypher-ed25519.h
|
||||
monocypher.cpp
|
||||
monocypher.h
|
||||
)
|
||||
Vendored
+167
@@ -0,0 +1,167 @@
|
||||
Monocypher as a whole is dual-licensed. Choose whichever licence you
|
||||
want from the two licences listed below.
|
||||
|
||||
The first licence is a regular 2-clause BSD licence. The second licence
|
||||
is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
to the public domain. The BSD licence serves as a fallback option.
|
||||
|
||||
See the individual files for specific information about who contributed
|
||||
to what file during which years. See below for special notes.
|
||||
|
||||
Licence 1 (2-clause BSD)
|
||||
------------------------
|
||||
|
||||
Copyright (c) 2017-2023, Loup Vaillant
|
||||
Copyright (c) 2017-2019, Michael Savage
|
||||
Copyright (c) 2017-2023, Fabio Scotoni
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Licence 2 (CC-0)
|
||||
----------------
|
||||
|
||||
> CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
> LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
> ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
> INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
> REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
> PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
> THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
> HEREUNDER.
|
||||
|
||||
### Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work
|
||||
of authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without
|
||||
fear of later claims of infringement build upon, modify, incorporate in
|
||||
other works, reuse and redistribute as freely as possible in any form
|
||||
whatsoever and for any purposes, including without limitation commercial
|
||||
purposes. These owners may contribute to the Commons to promote the
|
||||
ideal of a free culture and the further production of creative, cultural
|
||||
and scientific works, or to gain reputation or greater distribution for
|
||||
their Work in part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or
|
||||
she is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under
|
||||
its terms, with knowledge of his or her Copyright and Related Rights in
|
||||
the Work and the meaning and intended legal effect of CC0 on those
|
||||
rights.
|
||||
|
||||
1. **Copyright and Related Rights.** A Work made available under CC0 may
|
||||
be protected by copyright and related or neighboring rights
|
||||
("Copyright and Related Rights"). Copyright and Related Rights
|
||||
include, but are not limited to, the following:
|
||||
|
||||
- the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
- moral rights retained by the original author(s) and/or
|
||||
performer(s); publicity and privacy rights pertaining to a person's
|
||||
image or likeness depicted in a Work;
|
||||
- rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
- rights protecting the extraction, dissemination, use and reuse of
|
||||
data in a Work;
|
||||
- database rights (such as those arising under Directive 96/9/EC of
|
||||
the European Parliament and of the Council of 11 March 1996 on the
|
||||
legal protection of databases, and under any national
|
||||
implementation thereof, including any amended or successor version
|
||||
of such directive); and
|
||||
- other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. **Waiver.** To the greatest extent permitted by, but not in
|
||||
contravention of, applicable law, Affirmer hereby overtly, fully,
|
||||
permanently, irrevocably and unconditionally waives, abandons, and
|
||||
surrenders all of Affirmer's Copyright and Related Rights and
|
||||
associated claims and causes of action, whether now known or unknown
|
||||
(including existing as well as future claims and causes of action),
|
||||
in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"Waiver"). Affirmer makes the Waiver for the benefit of each member
|
||||
of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal
|
||||
or equitable action to disrupt the quiet enjoyment of the Work by the
|
||||
public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. **Public License Fallback.** Should any part of the Waiver for any
|
||||
reason be judged legally invalid or ineffective under applicable law,
|
||||
then the Waiver shall be preserved to the maximum extent permitted
|
||||
taking into account Affirmer's express Statement of Purpose. In
|
||||
addition, to the extent the Waiver is so judged Affirmer hereby
|
||||
grants to each affected person a royalty-free, non transferable, non
|
||||
sublicensable, non exclusive, irrevocable and unconditional license
|
||||
to exercise Affirmer's Copyright and Related Rights in the Work (i)
|
||||
in all territories worldwide, (ii) for the maximum duration provided
|
||||
by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and
|
||||
(iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "License"). The
|
||||
License shall be deemed effective as of the date CC0 was applied by
|
||||
Affirmer to the Work. Should any part of the License for any reason
|
||||
be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the
|
||||
remainder of the License, and in such case Affirmer hereby affirms
|
||||
that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any
|
||||
associated claims and causes of action with respect to the Work, in
|
||||
either case contrary to Affirmer's express Statement of Purpose.
|
||||
|
||||
4. **Limitations and Disclaimers.**
|
||||
|
||||
- No trademark or patent rights held by Affirmer are waived,
|
||||
abandoned, surrendered, licensed or otherwise affected by this
|
||||
document.
|
||||
- Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy,
|
||||
or the present or absence of errors, whether or not discoverable,
|
||||
all to the greatest extent permissible under applicable law.
|
||||
- Affirmer disclaims responsibility for clearing rights of other
|
||||
persons that may apply to the Work or any use thereof, including
|
||||
without limitation any person's Copyright and Related Rights in the
|
||||
Work. Further, Affirmer disclaims responsibility for obtaining any
|
||||
necessary consents, permissions or other rights required for any
|
||||
use of the Work.
|
||||
- Affirmer understands and acknowledges that Creative Commons is not
|
||||
a party to this document and has no duty or obligation with respect
|
||||
to this CC0 or use of the Work.
|
||||
Vendored
+164
@@ -0,0 +1,164 @@
|
||||
Monocypher
|
||||
----------
|
||||
|
||||
Monocypher is an easy to use, easy to deploy, auditable crypto library
|
||||
written in portable C. It approaches the size of [TweetNaCl][] and the
|
||||
speed of [libsodium][].
|
||||
|
||||
[Official site.](https://monocypher.org/)
|
||||
[Official releases.](https://monocypher.org/download/)
|
||||
|
||||
[libsodium]: https://libsodium.org
|
||||
[TweetNaCl]: https://tweetnacl.cr.yp.to/
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- [Authenticated Encryption][AEAD] with XChaCha20 and Poly1305
|
||||
(RFC 8439).
|
||||
- [Hashing and key derivation][HASH] with BLAKE2b (and [SHA-512][]).
|
||||
- [Password Hashing][PWH] with Argon2.
|
||||
- [Public Key Cryptography][PKC] with X25519 key exchanges.
|
||||
- [Public Key Signatures][EDDSA] with EdDSA and [Ed25519][].
|
||||
- [Steganography and PAKE][STEG] with [Elligator 2][ELLI].
|
||||
|
||||
[AEAD]: https://monocypher.org/manual/aead
|
||||
[HASH]: https://monocypher.org/manual/blake2
|
||||
[SHA-512]: https://monocypher.org/manual/sha-512
|
||||
[PWH]: https://monocypher.org/manual/argon2
|
||||
[PKC]: https://monocypher.org/manual/x25519
|
||||
[EDDSA]: https://monocypher.org/manual/eddsa
|
||||
[Ed25519]: https://monocypher.org/manual/ed25519
|
||||
[STEG]: https://monocypher.org/manual/elligator
|
||||
[ELLI]: https://elligator.org
|
||||
|
||||
|
||||
Manual
|
||||
------
|
||||
|
||||
The manual can be found at https://monocypher.org/manual/, and in the
|
||||
`doc/` folder.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
### Option 1: grab the sources
|
||||
|
||||
The easiest way to use Monocypher is to include `src/monocypher.h` and
|
||||
`src/monocypher.c` directly into your project. They compile as C (since
|
||||
C99) and C++ (since C++98).
|
||||
|
||||
If you need the optional SHA-512 or Ed25519, grab
|
||||
`src/optional/monocypher-ed25519.h` and
|
||||
`src/optional/monocypher-ed25519.c` as well.
|
||||
|
||||
### Option 2: grab the library
|
||||
|
||||
Run `make`, then grab the `src/monocypher.h` header and either the
|
||||
`lib/libmonocypher.a` or `lib/libmonocypher.so` library. The default
|
||||
compiler is `gcc -std=c99`, and the default flags are `-pedantic -Wall
|
||||
-Wextra -O3 -march=native`. If they don't work on your platform, you
|
||||
can change them like this:
|
||||
|
||||
$ make CC="clang -std=c11" CFLAGS="-O2"
|
||||
|
||||
### Option 3: install it on your system
|
||||
|
||||
Run `make`, then `make install` as root. This will install Monocypher in
|
||||
`/usr/local` by default. This can be changed with `PREFIX` and
|
||||
`DESTDIR`:
|
||||
|
||||
$ make install PREFIX="/opt"
|
||||
|
||||
Once installed, you may use `pkg-config` to compile and link your
|
||||
program. For instance:
|
||||
|
||||
$ gcc program.c $(pkg-config monocypher --cflags) -c
|
||||
$ gcc program.o $(pkg-config monocypher --libs) -o program
|
||||
|
||||
If for any reason you wish to avoid installing the man pages or the
|
||||
`pkg-config` file, you can use the following installation sub targets
|
||||
instead: `install-lib`, `install-doc`, and `install-pc`.
|
||||
|
||||
|
||||
Test suite
|
||||
----------
|
||||
|
||||
$ make test
|
||||
|
||||
It should display a nice printout of all the tests, ending with "All
|
||||
tests OK!". If you see "failure" or "Error" anywhere, something has gone
|
||||
wrong.
|
||||
|
||||
*Do not* use Monocypher without running those tests at least once.
|
||||
|
||||
The same test suite can be run under Clang sanitisers and Valgrind, and
|
||||
be checked for code coverage:
|
||||
|
||||
$ tests/test.sh
|
||||
$ tests/coverage.sh
|
||||
|
||||
|
||||
### Serious auditing
|
||||
|
||||
The code may be analysed more formally with [Frama-c][] and the
|
||||
[TIS interpreter][TIS]. To analyse the code with Frama-c, run:
|
||||
|
||||
$ tests/formal-analysis.sh
|
||||
$ tests/frama-c.sh
|
||||
|
||||
This will have Frama-c parse, and analyse the code, then launch a GUI.
|
||||
You must have Frama-c installed. See `frama-c.sh` for the recommended
|
||||
settings. To run the code under the TIS interpreter, run
|
||||
|
||||
$ tests/formal-analysis.sh
|
||||
$ tis-interpreter.sh --cc -Dvolatile= tests/formal-analysis/*.c
|
||||
|
||||
Notes:
|
||||
|
||||
- `tis-interpreter.sh` is part of TIS. If it is not in your path,
|
||||
adjust the command accordingly.
|
||||
|
||||
- The TIS interpreter sometimes fails to evaluate correct programs when
|
||||
they use the `volatile` keyword (which is only used as an attempt to
|
||||
prevent dead store elimination for memory wipes). The `-cc
|
||||
-Dvolatile=` option works around that bug by ignoring `volatile`
|
||||
altogether.
|
||||
|
||||
[Frama-c]:https://frama-c.com/
|
||||
[TIS]: https://trust-in-soft.com/tis-interpreter/
|
||||
|
||||
|
||||
Customisation
|
||||
-------------
|
||||
|
||||
Monocypher has optional compatibility with Ed25519. To have that, add
|
||||
`monocypher-ed25519.h` and `monocypher-ed25519.c` provided in
|
||||
`src/optional` to your project. If you compile or install Monocypher
|
||||
with the makefile, they will be automatically included.
|
||||
|
||||
Monocypher also has the `BLAKE2_NO_UNROLLING` preprocessor flag, which
|
||||
is activated by compiling monocypher.c with the `-DBLAKE2_NO_UNROLLING`
|
||||
option.
|
||||
|
||||
The `-DBLAKE2_NO_UNROLLING` option is a performance tweak. By default,
|
||||
Monocypher unrolls the BLAKE2b inner loop, because doing so is over 25%
|
||||
faster on modern processors. Some embedded processors however, run the
|
||||
unrolled loop _slower_ (possibly because of the cost of fetching 5KB of
|
||||
additional code). If you're using an embedded platform, try this
|
||||
option. The binary will be about 5KB smaller, and in some cases faster.
|
||||
|
||||
The `MONOCYPHER_CPP_NAMESPACE` preprocessor definition allows C++ users
|
||||
who compile Monocypher as C++ to wrap it in a namespace. When it is not
|
||||
defined (the default), we assume Monocypher is compiled as C, and an
|
||||
`extern "C"` declaration is added when we detect that the header is
|
||||
included in C++ code.
|
||||
|
||||
The `change-prefix.sh` script can rename all functions by replacing
|
||||
`crypto_` by a chosen prefix, so you can avoid name clashes. For
|
||||
instance, the following command changes all instances of `crypto_` by
|
||||
`foobar_` (note the absence of the underscore):
|
||||
|
||||
./change-prefix.sh foobar
|
||||
+500
@@ -0,0 +1,500 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#include "monocypher-ed25519.h"
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#endif
|
||||
|
||||
/////////////////
|
||||
/// Utilities ///
|
||||
/////////////////
|
||||
#define FOR(i, min, max) for (size_t i = min; i < max; i++)
|
||||
#define COPY(dst, src, size) FOR(_i_, 0, size) (dst)[_i_] = (src)[_i_]
|
||||
#define ZERO(buf, size) FOR(_i_, 0, size) (buf)[_i_] = 0
|
||||
#define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx)))
|
||||
#define WIPE_BUFFER(buffer) crypto_wipe(buffer, sizeof(buffer))
|
||||
#define MC_MIN(a, b) ((a) <= (b) ? (a) : (b))
|
||||
typedef uint8_t u8;
|
||||
typedef uint64_t u64;
|
||||
|
||||
// Returns the smallest positive integer y such that
|
||||
// (x + y) % pow_2 == 0
|
||||
// Basically, it's how many bytes we need to add to "align" x.
|
||||
// Only works when pow_2 is a power of 2.
|
||||
// Note: we use ~x+1 instead of -x to avoid compiler warnings
|
||||
static size_t align(size_t x, size_t pow_2)
|
||||
{
|
||||
return (~x + 1) & (pow_2 - 1);
|
||||
}
|
||||
|
||||
static u64 load64_be(const u8 s[8])
|
||||
{
|
||||
return((u64)s[0] << 56)
|
||||
| ((u64)s[1] << 48)
|
||||
| ((u64)s[2] << 40)
|
||||
| ((u64)s[3] << 32)
|
||||
| ((u64)s[4] << 24)
|
||||
| ((u64)s[5] << 16)
|
||||
| ((u64)s[6] << 8)
|
||||
| (u64)s[7];
|
||||
}
|
||||
|
||||
static void store64_be(u8 out[8], u64 in)
|
||||
{
|
||||
out[0] = (in >> 56) & 0xff;
|
||||
out[1] = (in >> 48) & 0xff;
|
||||
out[2] = (in >> 40) & 0xff;
|
||||
out[3] = (in >> 32) & 0xff;
|
||||
out[4] = (in >> 24) & 0xff;
|
||||
out[5] = (in >> 16) & 0xff;
|
||||
out[6] = (in >> 8) & 0xff;
|
||||
out[7] = in & 0xff;
|
||||
}
|
||||
|
||||
static void load64_be_buf (u64 *dst, const u8 *src, size_t size) {
|
||||
FOR(i, 0, size) { dst[i] = load64_be(src + i*8); }
|
||||
}
|
||||
|
||||
///////////////
|
||||
/// SHA 512 ///
|
||||
///////////////
|
||||
static u64 rot(u64 x, int c ) { return (x >> c) | (x << (64 - c)); }
|
||||
static u64 ch (u64 x, u64 y, u64 z) { return (x & y) ^ (~x & z); }
|
||||
static u64 maj(u64 x, u64 y, u64 z) { return (x & y) ^ ( x & z) ^ (y & z); }
|
||||
static u64 big_sigma0(u64 x) { return rot(x, 28) ^ rot(x, 34) ^ rot(x, 39); }
|
||||
static u64 big_sigma1(u64 x) { return rot(x, 14) ^ rot(x, 18) ^ rot(x, 41); }
|
||||
static u64 lit_sigma0(u64 x) { return rot(x, 1) ^ rot(x, 8) ^ (x >> 7); }
|
||||
static u64 lit_sigma1(u64 x) { return rot(x, 19) ^ rot(x, 61) ^ (x >> 6); }
|
||||
|
||||
static const u64 K[80] = {
|
||||
0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc,
|
||||
0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118,
|
||||
0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2,
|
||||
0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694,
|
||||
0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65,
|
||||
0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5,
|
||||
0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4,
|
||||
0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70,
|
||||
0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df,
|
||||
0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b,
|
||||
0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30,
|
||||
0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8,
|
||||
0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8,
|
||||
0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3,
|
||||
0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec,
|
||||
0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b,
|
||||
0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178,
|
||||
0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b,
|
||||
0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c,
|
||||
0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817
|
||||
};
|
||||
|
||||
static void sha512_compress(crypto_sha512_ctx *ctx)
|
||||
{
|
||||
u64 a = ctx->hash[0]; u64 b = ctx->hash[1];
|
||||
u64 c = ctx->hash[2]; u64 d = ctx->hash[3];
|
||||
u64 e = ctx->hash[4]; u64 f = ctx->hash[5];
|
||||
u64 g = ctx->hash[6]; u64 h = ctx->hash[7];
|
||||
|
||||
FOR (j, 0, 16) {
|
||||
u64 in = K[j] + ctx->input[j];
|
||||
u64 t1 = big_sigma1(e) + ch (e, f, g) + h + in;
|
||||
u64 t2 = big_sigma0(a) + maj(a, b, c);
|
||||
h = g; g = f; f = e; e = d + t1;
|
||||
d = c; c = b; b = a; a = t1 + t2;
|
||||
}
|
||||
size_t i16 = 0;
|
||||
FOR(i, 1, 5) {
|
||||
i16 += 16;
|
||||
FOR (j, 0, 16) {
|
||||
ctx->input[j] += lit_sigma1(ctx->input[(j- 2) & 15]);
|
||||
ctx->input[j] += lit_sigma0(ctx->input[(j-15) & 15]);
|
||||
ctx->input[j] += ctx->input[(j- 7) & 15];
|
||||
u64 in = K[i16 + j] + ctx->input[j];
|
||||
u64 t1 = big_sigma1(e) + ch (e, f, g) + h + in;
|
||||
u64 t2 = big_sigma0(a) + maj(a, b, c);
|
||||
h = g; g = f; f = e; e = d + t1;
|
||||
d = c; c = b; b = a; a = t1 + t2;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->hash[0] += a; ctx->hash[1] += b;
|
||||
ctx->hash[2] += c; ctx->hash[3] += d;
|
||||
ctx->hash[4] += e; ctx->hash[5] += f;
|
||||
ctx->hash[6] += g; ctx->hash[7] += h;
|
||||
}
|
||||
|
||||
// Write 1 input byte
|
||||
static void sha512_set_input(crypto_sha512_ctx *ctx, u8 input)
|
||||
{
|
||||
size_t word = ctx->input_idx >> 3;
|
||||
size_t byte = ctx->input_idx & 7;
|
||||
ctx->input[word] |= (u64)input << (8 * (7 - byte));
|
||||
}
|
||||
|
||||
// Increment a 128-bit "word".
|
||||
static void sha512_incr(u64 x[2], u64 y)
|
||||
{
|
||||
x[1] += y;
|
||||
if (x[1] < y) {
|
||||
x[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_init(crypto_sha512_ctx *ctx)
|
||||
{
|
||||
ctx->hash[0] = 0x6a09e667f3bcc908;
|
||||
ctx->hash[1] = 0xbb67ae8584caa73b;
|
||||
ctx->hash[2] = 0x3c6ef372fe94f82b;
|
||||
ctx->hash[3] = 0xa54ff53a5f1d36f1;
|
||||
ctx->hash[4] = 0x510e527fade682d1;
|
||||
ctx->hash[5] = 0x9b05688c2b3e6c1f;
|
||||
ctx->hash[6] = 0x1f83d9abfb41bd6b;
|
||||
ctx->hash[7] = 0x5be0cd19137e2179;
|
||||
ctx->input_size[0] = 0;
|
||||
ctx->input_size[1] = 0;
|
||||
ctx->input_idx = 0;
|
||||
ZERO(ctx->input, 16);
|
||||
}
|
||||
|
||||
void crypto_sha512_update(crypto_sha512_ctx *ctx,
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
// Avoid undefined NULL pointer increments with empty messages
|
||||
if (message_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Align ourselves with word boundaries
|
||||
if ((ctx->input_idx & 7) != 0) {
|
||||
size_t nb_bytes = MC_MIN(align(ctx->input_idx, 8), message_size);
|
||||
FOR (i, 0, nb_bytes) {
|
||||
sha512_set_input(ctx, message[i]);
|
||||
ctx->input_idx++;
|
||||
}
|
||||
message += nb_bytes;
|
||||
message_size -= nb_bytes;
|
||||
}
|
||||
|
||||
// Align ourselves with block boundaries
|
||||
if ((ctx->input_idx & 127) != 0) {
|
||||
size_t nb_words = MC_MIN(align(ctx->input_idx, 128), message_size) >> 3;
|
||||
load64_be_buf(ctx->input + (ctx->input_idx >> 3), message, nb_words);
|
||||
ctx->input_idx += nb_words << 3;
|
||||
message += nb_words << 3;
|
||||
message_size -= nb_words << 3;
|
||||
}
|
||||
|
||||
// Compress block if needed
|
||||
if (ctx->input_idx == 128) {
|
||||
sha512_incr(ctx->input_size, 1024); // size is in bits
|
||||
sha512_compress(ctx);
|
||||
ctx->input_idx = 0;
|
||||
ZERO(ctx->input, 16);
|
||||
}
|
||||
|
||||
// Process the message block by block
|
||||
FOR (i, 0, message_size >> 7) { // number of blocks
|
||||
load64_be_buf(ctx->input, message, 16);
|
||||
sha512_incr(ctx->input_size, 1024); // size is in bits
|
||||
sha512_compress(ctx);
|
||||
ctx->input_idx = 0;
|
||||
ZERO(ctx->input, 16);
|
||||
message += 128;
|
||||
}
|
||||
message_size &= 127;
|
||||
|
||||
if (message_size != 0) {
|
||||
// Remaining words
|
||||
size_t nb_words = message_size >> 3;
|
||||
load64_be_buf(ctx->input, message, nb_words);
|
||||
ctx->input_idx += nb_words << 3;
|
||||
message += nb_words << 3;
|
||||
message_size -= nb_words << 3;
|
||||
|
||||
// Remaining bytes
|
||||
FOR (i, 0, message_size) {
|
||||
sha512_set_input(ctx, message[i]);
|
||||
ctx->input_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_final(crypto_sha512_ctx *ctx, u8 hash[64])
|
||||
{
|
||||
// Add padding bit
|
||||
if (ctx->input_idx == 0) {
|
||||
ZERO(ctx->input, 16);
|
||||
}
|
||||
sha512_set_input(ctx, 128);
|
||||
|
||||
// Update size
|
||||
sha512_incr(ctx->input_size, ctx->input_idx * 8);
|
||||
|
||||
// Compress penultimate block (if any)
|
||||
if (ctx->input_idx > 111) {
|
||||
sha512_compress(ctx);
|
||||
ZERO(ctx->input, 14);
|
||||
}
|
||||
// Compress last block
|
||||
ctx->input[14] = ctx->input_size[0];
|
||||
ctx->input[15] = ctx->input_size[1];
|
||||
sha512_compress(ctx);
|
||||
|
||||
// Copy hash to output (big endian)
|
||||
FOR (i, 0, 8) {
|
||||
store64_be(hash + i*8, ctx->hash[i]);
|
||||
}
|
||||
|
||||
WIPE_CTX(ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512(u8 hash[64], const u8 *message, size_t message_size)
|
||||
{
|
||||
crypto_sha512_ctx ctx;
|
||||
crypto_sha512_init (&ctx);
|
||||
crypto_sha512_update(&ctx, message, message_size);
|
||||
crypto_sha512_final (&ctx, hash);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// HMAC SHA 512 ///
|
||||
////////////////////
|
||||
void crypto_sha512_hmac_init(crypto_sha512_hmac_ctx *ctx,
|
||||
const u8 *key, size_t key_size)
|
||||
{
|
||||
// hash key if it is too long
|
||||
if (key_size > 128) {
|
||||
crypto_sha512(ctx->key, key, key_size);
|
||||
key = ctx->key;
|
||||
key_size = 64;
|
||||
}
|
||||
// Compute inner key: padded key XOR 0x36
|
||||
FOR (i, 0, key_size) { ctx->key[i] = key[i] ^ 0x36; }
|
||||
FOR (i, key_size, 128) { ctx->key[i] = 0x36; }
|
||||
// Start computing inner hash
|
||||
crypto_sha512_init (&ctx->ctx);
|
||||
crypto_sha512_update(&ctx->ctx, ctx->key, 128);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac_update(crypto_sha512_hmac_ctx *ctx,
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
crypto_sha512_update(&ctx->ctx, message, message_size);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac_final(crypto_sha512_hmac_ctx *ctx, u8 hmac[64])
|
||||
{
|
||||
// Finish computing inner hash
|
||||
crypto_sha512_final(&ctx->ctx, hmac);
|
||||
// Compute outer key: padded key XOR 0x5c
|
||||
FOR (i, 0, 128) {
|
||||
ctx->key[i] ^= 0x36 ^ 0x5c;
|
||||
}
|
||||
// Compute outer hash
|
||||
crypto_sha512_init (&ctx->ctx);
|
||||
crypto_sha512_update(&ctx->ctx, ctx->key , 128);
|
||||
crypto_sha512_update(&ctx->ctx, hmac, 64);
|
||||
crypto_sha512_final (&ctx->ctx, hmac); // outer hash
|
||||
WIPE_CTX(ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac(u8 hmac[64], const u8 *key, size_t key_size,
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
crypto_sha512_hmac_ctx ctx;
|
||||
crypto_sha512_hmac_init (&ctx, key, key_size);
|
||||
crypto_sha512_hmac_update(&ctx, message, message_size);
|
||||
crypto_sha512_hmac_final (&ctx, hmac);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// HKDF SHA 512 ///
|
||||
////////////////////
|
||||
void crypto_sha512_hkdf_expand(u8 *okm, size_t okm_size,
|
||||
const u8 *prk, size_t prk_size,
|
||||
const u8 *info, size_t info_size)
|
||||
{
|
||||
int not_first = 0;
|
||||
u8 ctr = 1;
|
||||
u8 blk[64];
|
||||
|
||||
while (okm_size > 0) {
|
||||
size_t out_size = MC_MIN(okm_size, sizeof(blk));
|
||||
|
||||
crypto_sha512_hmac_ctx ctx;
|
||||
crypto_sha512_hmac_init(&ctx, prk , prk_size);
|
||||
if (not_first) {
|
||||
// For some reason HKDF uses some kind of CBC mode.
|
||||
// For some reason CTR mode alone wasn't enough.
|
||||
// Like what, they didn't trust HMAC in 2010? Really??
|
||||
crypto_sha512_hmac_update(&ctx, blk , sizeof(blk));
|
||||
}
|
||||
crypto_sha512_hmac_update(&ctx, info, info_size);
|
||||
crypto_sha512_hmac_update(&ctx, &ctr, 1);
|
||||
crypto_sha512_hmac_final(&ctx, blk);
|
||||
|
||||
COPY(okm, blk, out_size);
|
||||
|
||||
not_first = 1;
|
||||
okm += out_size;
|
||||
okm_size -= out_size;
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_hkdf(u8 *okm , size_t okm_size,
|
||||
const u8 *ikm , size_t ikm_size,
|
||||
const u8 *salt, size_t salt_size,
|
||||
const u8 *info, size_t info_size)
|
||||
{
|
||||
// Extract
|
||||
u8 prk[64];
|
||||
crypto_sha512_hmac(prk, salt, salt_size, ikm, ikm_size);
|
||||
|
||||
// Expand
|
||||
crypto_sha512_hkdf_expand(okm, okm_size, prk, sizeof(prk), info, info_size);
|
||||
}
|
||||
|
||||
///////////////
|
||||
/// Ed25519 ///
|
||||
///////////////
|
||||
void crypto_ed25519_key_pair(u8 secret_key[64], u8 public_key[32], u8 seed[32])
|
||||
{
|
||||
u8 a[64];
|
||||
COPY(a, seed, 32); // a[ 0..31] = seed
|
||||
crypto_wipe(seed, 32);
|
||||
COPY(secret_key, a, 32); // secret key = seed
|
||||
crypto_sha512(a, a, 32); // a[ 0..31] = scalar
|
||||
crypto_eddsa_trim_scalar(a, a); // a[ 0..31] = trimmed scalar
|
||||
crypto_eddsa_scalarbase(public_key, a); // public key = [trimmed scalar]B
|
||||
COPY(secret_key + 32, public_key, 32); // secret key includes public half
|
||||
WIPE_BUFFER(a);
|
||||
}
|
||||
|
||||
static void hash_reduce(u8 h[32],
|
||||
const u8 *a, size_t a_size,
|
||||
const u8 *b, size_t b_size,
|
||||
const u8 *c, size_t c_size,
|
||||
const u8 *d, size_t d_size)
|
||||
{
|
||||
u8 hash[64];
|
||||
crypto_sha512_ctx ctx;
|
||||
crypto_sha512_init (&ctx);
|
||||
crypto_sha512_update(&ctx, a, a_size);
|
||||
crypto_sha512_update(&ctx, b, b_size);
|
||||
crypto_sha512_update(&ctx, c, c_size);
|
||||
crypto_sha512_update(&ctx, d, d_size);
|
||||
crypto_sha512_final (&ctx, hash);
|
||||
crypto_eddsa_reduce(h, hash);
|
||||
}
|
||||
|
||||
static void ed25519_dom_sign(u8 signature [64], const u8 secret_key[32],
|
||||
const u8 *dom, size_t dom_size,
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
u8 a[64]; // secret scalar and prefix
|
||||
u8 r[32]; // secret deterministic "random" nonce
|
||||
u8 h[32]; // publically verifiable hash of the message (not wiped)
|
||||
u8 R[32]; // first half of the signature (allows overlapping inputs)
|
||||
const u8 *pk = secret_key + 32;
|
||||
|
||||
crypto_sha512(a, secret_key, 32);
|
||||
crypto_eddsa_trim_scalar(a, a);
|
||||
hash_reduce(r, dom, dom_size, a + 32, 32, message, message_size, 0, 0);
|
||||
crypto_eddsa_scalarbase(R, r);
|
||||
hash_reduce(h, dom, dom_size, R, 32, pk, 32, message, message_size);
|
||||
COPY(signature, R, 32);
|
||||
crypto_eddsa_mul_add(signature + 32, h, a, r);
|
||||
|
||||
WIPE_BUFFER(a);
|
||||
WIPE_BUFFER(r);
|
||||
}
|
||||
|
||||
void crypto_ed25519_sign(u8 signature [64], const u8 secret_key[64],
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
ed25519_dom_sign(signature, secret_key, 0, 0, message, message_size);
|
||||
}
|
||||
|
||||
int crypto_ed25519_check(const u8 signature[64], const u8 public_key[32],
|
||||
const u8 *msg, size_t msg_size)
|
||||
{
|
||||
u8 h_ram[32];
|
||||
hash_reduce(h_ram, signature, 32, public_key, 32, msg, msg_size, 0, 0);
|
||||
return crypto_eddsa_check_equation(signature, public_key, h_ram);
|
||||
}
|
||||
|
||||
static const u8 domain[34] = "SigEd25519 no Ed25519 collisions\1";
|
||||
|
||||
void crypto_ed25519_ph_sign(uint8_t signature[64], const uint8_t secret_key[64],
|
||||
const uint8_t message_hash[64])
|
||||
{
|
||||
ed25519_dom_sign(signature, secret_key, domain, sizeof(domain),
|
||||
message_hash, 64);
|
||||
}
|
||||
|
||||
int crypto_ed25519_ph_check(const uint8_t sig[64], const uint8_t pk[32],
|
||||
const uint8_t msg_hash[64])
|
||||
{
|
||||
u8 h_ram[32];
|
||||
hash_reduce(h_ram, domain, sizeof(domain), sig, 32, pk, 32, msg_hash, 64);
|
||||
return crypto_eddsa_check_equation(sig, pk, h_ram);
|
||||
}
|
||||
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
}
|
||||
#endif
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#ifndef ED25519_H
|
||||
#define ED25519_H
|
||||
|
||||
#include "monocypher.h"
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#elif defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
////////////////////////
|
||||
/// Type definitions ///
|
||||
////////////////////////
|
||||
|
||||
// Do not rely on the size or content on any of those types,
|
||||
// they may change without notice.
|
||||
typedef struct {
|
||||
uint64_t hash[8];
|
||||
uint64_t input[16];
|
||||
uint64_t input_size[2];
|
||||
size_t input_idx;
|
||||
} crypto_sha512_ctx;
|
||||
|
||||
typedef struct {
|
||||
uint8_t key[128];
|
||||
crypto_sha512_ctx ctx;
|
||||
} crypto_sha512_hmac_ctx;
|
||||
|
||||
|
||||
// SHA 512
|
||||
// -------
|
||||
void crypto_sha512_init (crypto_sha512_ctx *ctx);
|
||||
void crypto_sha512_update(crypto_sha512_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_sha512_final (crypto_sha512_ctx *ctx, uint8_t hash[64]);
|
||||
void crypto_sha512(uint8_t hash[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512 HMAC
|
||||
// ------------
|
||||
void crypto_sha512_hmac_init(crypto_sha512_hmac_ctx *ctx,
|
||||
const uint8_t *key, size_t key_size);
|
||||
void crypto_sha512_hmac_update(crypto_sha512_hmac_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_sha512_hmac_final(crypto_sha512_hmac_ctx *ctx, uint8_t hmac[64]);
|
||||
void crypto_sha512_hmac(uint8_t hmac[64],
|
||||
const uint8_t *key , size_t key_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512 HKDF
|
||||
// ------------
|
||||
void crypto_sha512_hkdf_expand(uint8_t *okm, size_t okm_size,
|
||||
const uint8_t *prk, size_t prk_size,
|
||||
const uint8_t *info, size_t info_size);
|
||||
void crypto_sha512_hkdf(uint8_t *okm , size_t okm_size,
|
||||
const uint8_t *ikm , size_t ikm_size,
|
||||
const uint8_t *salt, size_t salt_size,
|
||||
const uint8_t *info, size_t info_size);
|
||||
|
||||
// Ed25519
|
||||
// -------
|
||||
// Signatures (EdDSA with curve25519 + SHA-512)
|
||||
// --------------------------------------------
|
||||
void crypto_ed25519_key_pair(uint8_t secret_key[64],
|
||||
uint8_t public_key[32],
|
||||
uint8_t seed[32]);
|
||||
void crypto_ed25519_sign(uint8_t signature [64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
int crypto_ed25519_check(const uint8_t signature [64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Pre-hash variants
|
||||
void crypto_ed25519_ph_sign(uint8_t signature [64],
|
||||
const uint8_t secret_key [64],
|
||||
const uint8_t message_hash[64]);
|
||||
int crypto_ed25519_ph_check(const uint8_t signature [64],
|
||||
const uint8_t public_key [32],
|
||||
const uint8_t message_hash[64]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ED25519_H
|
||||
+2956
File diff suppressed because it is too large
Load Diff
Vendored
+321
@@ -0,0 +1,321 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#ifndef MONOCYPHER_H
|
||||
#define MONOCYPHER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#elif defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Constant time comparisons
|
||||
// -------------------------
|
||||
|
||||
// Return 0 if a and b are equal, -1 otherwise
|
||||
int crypto_verify16(const uint8_t a[16], const uint8_t b[16]);
|
||||
int crypto_verify32(const uint8_t a[32], const uint8_t b[32]);
|
||||
int crypto_verify64(const uint8_t a[64], const uint8_t b[64]);
|
||||
|
||||
|
||||
// Erase sensitive data
|
||||
// --------------------
|
||||
void crypto_wipe(void *secret, size_t size);
|
||||
|
||||
|
||||
// Authenticated encryption
|
||||
// ------------------------
|
||||
void crypto_aead_lock(uint8_t *cipher_text,
|
||||
uint8_t mac [16],
|
||||
const uint8_t key [32],
|
||||
const uint8_t nonce[24],
|
||||
const uint8_t *ad, size_t ad_size,
|
||||
const uint8_t *plain_text, size_t text_size);
|
||||
int crypto_aead_unlock(uint8_t *plain_text,
|
||||
const uint8_t mac [16],
|
||||
const uint8_t key [32],
|
||||
const uint8_t nonce[24],
|
||||
const uint8_t *ad, size_t ad_size,
|
||||
const uint8_t *cipher_text, size_t text_size);
|
||||
|
||||
// Authenticated stream
|
||||
// --------------------
|
||||
typedef struct {
|
||||
uint64_t counter;
|
||||
uint8_t key[32];
|
||||
uint8_t nonce[8];
|
||||
} crypto_aead_ctx;
|
||||
|
||||
void crypto_aead_init_x(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[24]);
|
||||
void crypto_aead_init_djb(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[8]);
|
||||
void crypto_aead_init_ietf(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[12]);
|
||||
|
||||
void crypto_aead_write(crypto_aead_ctx *ctx,
|
||||
uint8_t *cipher_text,
|
||||
uint8_t mac[16],
|
||||
const uint8_t *ad , size_t ad_size,
|
||||
const uint8_t *plain_text, size_t text_size);
|
||||
int crypto_aead_read(crypto_aead_ctx *ctx,
|
||||
uint8_t *plain_text,
|
||||
const uint8_t mac[16],
|
||||
const uint8_t *ad , size_t ad_size,
|
||||
const uint8_t *cipher_text, size_t text_size);
|
||||
|
||||
|
||||
// General purpose hash (BLAKE2b)
|
||||
// ------------------------------
|
||||
|
||||
// Direct interface
|
||||
void crypto_blake2b(uint8_t *hash, size_t hash_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
void crypto_blake2b_keyed(uint8_t *hash, size_t hash_size,
|
||||
const uint8_t *key, size_t key_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Incremental interface
|
||||
typedef struct {
|
||||
// Do not rely on the size or contents of this type,
|
||||
// for they may change without notice.
|
||||
uint64_t hash[8];
|
||||
uint64_t input_offset[2];
|
||||
uint64_t input[16];
|
||||
size_t input_idx;
|
||||
size_t hash_size;
|
||||
} crypto_blake2b_ctx;
|
||||
|
||||
void crypto_blake2b_init(crypto_blake2b_ctx *ctx, size_t hash_size);
|
||||
void crypto_blake2b_keyed_init(crypto_blake2b_ctx *ctx, size_t hash_size,
|
||||
const uint8_t *key, size_t key_size);
|
||||
void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_blake2b_final(crypto_blake2b_ctx *ctx, uint8_t *hash);
|
||||
|
||||
|
||||
// Password key derivation (Argon2)
|
||||
// --------------------------------
|
||||
#define CRYPTO_ARGON2_D 0
|
||||
#define CRYPTO_ARGON2_I 1
|
||||
#define CRYPTO_ARGON2_ID 2
|
||||
|
||||
typedef struct {
|
||||
uint32_t algorithm; // Argon2d, Argon2i, Argon2id
|
||||
uint32_t nb_blocks; // memory hardness, >= 8 * nb_lanes
|
||||
uint32_t nb_passes; // CPU hardness, >= 1 (>= 3 recommended for Argon2i)
|
||||
uint32_t nb_lanes; // parallelism level (single threaded anyway)
|
||||
} crypto_argon2_config;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *pass;
|
||||
const uint8_t *salt;
|
||||
uint32_t pass_size;
|
||||
uint32_t salt_size; // 16 bytes recommended
|
||||
} crypto_argon2_inputs;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *key; // may be NULL if no key
|
||||
const uint8_t *ad; // may be NULL if no additional data
|
||||
uint32_t key_size; // 0 if no key (32 bytes recommended otherwise)
|
||||
uint32_t ad_size; // 0 if no additional data
|
||||
} crypto_argon2_extras;
|
||||
|
||||
extern const crypto_argon2_extras crypto_argon2_no_extras;
|
||||
|
||||
void crypto_argon2(uint8_t *hash, uint32_t hash_size, void *work_area,
|
||||
crypto_argon2_config config,
|
||||
crypto_argon2_inputs inputs,
|
||||
crypto_argon2_extras extras);
|
||||
|
||||
|
||||
// Key exchange (X-25519)
|
||||
// ----------------------
|
||||
|
||||
// Shared secrets are not quite random.
|
||||
// Hash them to derive an actual shared key.
|
||||
void crypto_x25519_public_key(uint8_t public_key[32],
|
||||
const uint8_t secret_key[32]);
|
||||
void crypto_x25519(uint8_t raw_shared_secret[32],
|
||||
const uint8_t your_secret_key [32],
|
||||
const uint8_t their_public_key [32]);
|
||||
|
||||
// Conversion to EdDSA
|
||||
void crypto_x25519_to_eddsa(uint8_t eddsa[32], const uint8_t x25519[32]);
|
||||
|
||||
// scalar "division"
|
||||
// Used for OPRF. Be aware that exponential blinding is less secure
|
||||
// than Diffie-Hellman key exchange.
|
||||
void crypto_x25519_inverse(uint8_t blind_salt [32],
|
||||
const uint8_t private_key[32],
|
||||
const uint8_t curve_point[32]);
|
||||
|
||||
// "Dirty" versions of x25519_public_key().
|
||||
// Use with crypto_elligator_rev().
|
||||
// Leaks 3 bits of the private key.
|
||||
void crypto_x25519_dirty_small(uint8_t pk[32], const uint8_t sk[32]);
|
||||
void crypto_x25519_dirty_fast (uint8_t pk[32], const uint8_t sk[32]);
|
||||
|
||||
|
||||
// Signatures
|
||||
// ----------
|
||||
|
||||
// EdDSA with curve25519 + BLAKE2b
|
||||
void crypto_eddsa_key_pair(uint8_t secret_key[64],
|
||||
uint8_t public_key[32],
|
||||
uint8_t seed[32]);
|
||||
void crypto_eddsa_sign(uint8_t signature [64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
int crypto_eddsa_check(const uint8_t signature [64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Conversion to X25519
|
||||
void crypto_eddsa_to_x25519(uint8_t x25519[32], const uint8_t eddsa[32]);
|
||||
|
||||
// EdDSA building blocks
|
||||
void crypto_eddsa_trim_scalar(uint8_t out[32], const uint8_t in[32]);
|
||||
void crypto_eddsa_reduce(uint8_t reduced[32], const uint8_t expanded[64]);
|
||||
void crypto_eddsa_mul_add(uint8_t r[32],
|
||||
const uint8_t a[32],
|
||||
const uint8_t b[32],
|
||||
const uint8_t c[32]);
|
||||
void crypto_eddsa_scalarbase(uint8_t point[32], const uint8_t scalar[32]);
|
||||
int crypto_eddsa_check_equation(const uint8_t signature[64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t h_ram[32]);
|
||||
|
||||
|
||||
// Chacha20
|
||||
// --------
|
||||
|
||||
// Specialised hash.
|
||||
// Used to hash X25519 shared secrets.
|
||||
void crypto_chacha20_h(uint8_t out[32],
|
||||
const uint8_t key[32],
|
||||
const uint8_t in [16]);
|
||||
|
||||
// Unauthenticated stream cipher.
|
||||
// Don't forget to add authentication.
|
||||
uint64_t crypto_chacha20_djb(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[8],
|
||||
uint64_t ctr);
|
||||
uint32_t crypto_chacha20_ietf(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[12],
|
||||
uint32_t ctr);
|
||||
uint64_t crypto_chacha20_x(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[24],
|
||||
uint64_t ctr);
|
||||
|
||||
|
||||
// Poly 1305
|
||||
// ---------
|
||||
|
||||
// This is a *one time* authenticator.
|
||||
// Disclosing the mac reveals the key.
|
||||
// See crypto_lock() on how to use it properly.
|
||||
|
||||
// Direct interface
|
||||
void crypto_poly1305(uint8_t mac[16],
|
||||
const uint8_t *message, size_t message_size,
|
||||
const uint8_t key[32]);
|
||||
|
||||
// Incremental interface
|
||||
typedef struct {
|
||||
// Do not rely on the size or contents of this type,
|
||||
// for they may change without notice.
|
||||
uint8_t c[16]; // chunk of the message
|
||||
size_t c_idx; // How many bytes are there in the chunk.
|
||||
uint32_t r [4]; // constant multiplier (from the secret key)
|
||||
uint32_t pad[4]; // random number added at the end (from the secret key)
|
||||
uint32_t h [5]; // accumulated hash
|
||||
} crypto_poly1305_ctx;
|
||||
|
||||
void crypto_poly1305_init (crypto_poly1305_ctx *ctx, const uint8_t key[32]);
|
||||
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_poly1305_final (crypto_poly1305_ctx *ctx, uint8_t mac[16]);
|
||||
|
||||
|
||||
// Elligator 2
|
||||
// -----------
|
||||
|
||||
// Elligator mappings proper
|
||||
void crypto_elligator_map(uint8_t curve [32], const uint8_t hidden[32]);
|
||||
int crypto_elligator_rev(uint8_t hidden[32], const uint8_t curve [32],
|
||||
uint8_t tweak);
|
||||
|
||||
// Easy to use key pair generation
|
||||
void crypto_elligator_key_pair(uint8_t hidden[32], uint8_t secret_key[32],
|
||||
uint8_t seed[32]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MONOCYPHER_H
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
add_files(
|
||||
json.hpp
|
||||
)
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Niels Lohmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Vendored
+24765
File diff suppressed because it is too large
Load Diff
Vendored
+117
-66
@@ -32,7 +32,7 @@ extern "C" {
|
||||
#define GLAPI extern
|
||||
#endif
|
||||
|
||||
#define GL_GLEXT_VERSION 20201119
|
||||
#define GL_GLEXT_VERSION 20231129
|
||||
|
||||
#include "khrplatform.h"
|
||||
|
||||
@@ -5397,12 +5397,12 @@ typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severi
|
||||
typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
|
||||
typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);
|
||||
typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam);
|
||||
typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufSize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
|
||||
typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufSize, GLenum *categories, GLenum *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
|
||||
GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);
|
||||
GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam);
|
||||
GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufSize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
|
||||
GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufSize, GLenum *categories, GLenum *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
|
||||
#endif
|
||||
#endif /* GL_AMD_debug_output */
|
||||
|
||||
@@ -7370,6 +7370,16 @@ GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1,
|
||||
#endif
|
||||
#endif /* GL_EXT_framebuffer_blit */
|
||||
|
||||
#ifndef GL_EXT_framebuffer_blit_layers
|
||||
#define GL_EXT_framebuffer_blit_layers 1
|
||||
typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERLAYERSEXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERLAYEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint srcLayer, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLint dstLayer, GLbitfield mask, GLenum filter);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBlitFramebufferLayersEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
GLAPI void APIENTRY glBlitFramebufferLayerEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint srcLayer, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLint dstLayer, GLbitfield mask, GLenum filter);
|
||||
#endif
|
||||
#endif /* GL_EXT_framebuffer_blit_layers */
|
||||
|
||||
#ifndef GL_EXT_framebuffer_multisample
|
||||
#define GL_EXT_framebuffer_multisample 1
|
||||
#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
|
||||
@@ -7524,7 +7534,6 @@ GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index,
|
||||
|
||||
#ifndef GL_EXT_gpu_shader4
|
||||
#define GL_EXT_gpu_shader4 1
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD
|
||||
#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0
|
||||
#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1
|
||||
#define GL_SAMPLER_BUFFER_EXT 0x8DC2
|
||||
@@ -7552,6 +7561,7 @@ GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index,
|
||||
#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8
|
||||
#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904
|
||||
#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD
|
||||
typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params);
|
||||
typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
|
||||
typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name);
|
||||
@@ -7563,6 +7573,29 @@ typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count,
|
||||
typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params);
|
||||
GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name);
|
||||
@@ -7575,6 +7608,29 @@ GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuin
|
||||
GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value);
|
||||
GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value);
|
||||
GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value);
|
||||
GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x);
|
||||
GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y);
|
||||
GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z);
|
||||
GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w);
|
||||
GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x);
|
||||
GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y);
|
||||
GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z);
|
||||
GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
|
||||
GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v);
|
||||
GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
|
||||
GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params);
|
||||
#endif
|
||||
#endif /* GL_EXT_gpu_shader4 */
|
||||
|
||||
@@ -8168,6 +8224,10 @@ GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers);
|
||||
#define GL_EXT_shader_integer_mix 1
|
||||
#endif /* GL_EXT_shader_integer_mix */
|
||||
|
||||
#ifndef GL_EXT_shader_samples_identical
|
||||
#define GL_EXT_shader_samples_identical 1
|
||||
#endif /* GL_EXT_shader_samples_identical */
|
||||
|
||||
#ifndef GL_EXT_shadow_funcs
|
||||
#define GL_EXT_shadow_funcs 1
|
||||
#endif /* GL_EXT_shadow_funcs */
|
||||
@@ -8536,6 +8596,11 @@ GLAPI void APIENTRY glTextureNormalEXT (GLenum mode);
|
||||
#define GL_SR8_EXT 0x8FBD
|
||||
#endif /* GL_EXT_texture_sRGB_R8 */
|
||||
|
||||
#ifndef GL_EXT_texture_sRGB_RG8
|
||||
#define GL_EXT_texture_sRGB_RG8 1
|
||||
#define GL_SRG8_EXT 0x8FBE
|
||||
#endif /* GL_EXT_texture_sRGB_RG8 */
|
||||
|
||||
#ifndef GL_EXT_texture_sRGB_decode
|
||||
#define GL_EXT_texture_sRGB_decode 1
|
||||
#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48
|
||||
@@ -8574,6 +8639,36 @@ GLAPI void APIENTRY glTextureNormalEXT (GLenum mode);
|
||||
#define GL_RGBA_SNORM 0x8F93
|
||||
#endif /* GL_EXT_texture_snorm */
|
||||
|
||||
#ifndef GL_EXT_texture_storage
|
||||
#define GL_EXT_texture_storage 1
|
||||
#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
|
||||
#define GL_RGBA32F_EXT 0x8814
|
||||
#define GL_RGB32F_EXT 0x8815
|
||||
#define GL_ALPHA32F_EXT 0x8816
|
||||
#define GL_LUMINANCE32F_EXT 0x8818
|
||||
#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
|
||||
#define GL_RGBA16F_EXT 0x881A
|
||||
#define GL_RGB16F_EXT 0x881B
|
||||
#define GL_ALPHA16F_EXT 0x881C
|
||||
#define GL_LUMINANCE16F_EXT 0x881E
|
||||
#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
|
||||
#define GL_BGRA8_EXT 0x93A1
|
||||
#define GL_R8_EXT 0x8229
|
||||
#define GL_RG8_EXT 0x822B
|
||||
#define GL_R32F_EXT 0x822E
|
||||
#define GL_RG32F_EXT 0x8230
|
||||
#define GL_R16F_EXT 0x822D
|
||||
#define GL_RG16F_EXT 0x822F
|
||||
typedef void (APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
|
||||
typedef void (APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
typedef void (APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
|
||||
GLAPI void APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
GLAPI void APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
|
||||
#endif
|
||||
#endif /* GL_EXT_texture_storage */
|
||||
|
||||
#ifndef GL_EXT_texture_swizzle
|
||||
#define GL_EXT_texture_swizzle 1
|
||||
#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42
|
||||
@@ -10163,12 +10258,6 @@ typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s,
|
||||
typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
|
||||
typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
|
||||
typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
|
||||
typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
|
||||
typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
|
||||
typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);
|
||||
@@ -10181,6 +10270,12 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, c
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
|
||||
typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
|
||||
typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
|
||||
typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
|
||||
typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y);
|
||||
GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v);
|
||||
@@ -10210,12 +10305,6 @@ GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t,
|
||||
GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
|
||||
GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog);
|
||||
GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog);
|
||||
GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
|
||||
GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight);
|
||||
GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight);
|
||||
GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x);
|
||||
GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y);
|
||||
@@ -10228,6 +10317,12 @@ GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfN
|
||||
GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog);
|
||||
GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog);
|
||||
GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
|
||||
GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v);
|
||||
GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight);
|
||||
GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight);
|
||||
#endif
|
||||
#endif /* GL_NV_half_float */
|
||||
|
||||
@@ -10630,7 +10725,7 @@ typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenu
|
||||
typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode);
|
||||
typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
|
||||
typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
|
||||
typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]);
|
||||
typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint *baseAndCount);
|
||||
typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
|
||||
typedef GLenum (APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs);
|
||||
@@ -10695,7 +10790,7 @@ GLAPI void APIENTRY glStencilThenCoverFillPathNV (GLuint path, GLenum fillMode,
|
||||
GLAPI void APIENTRY glStencilThenCoverStrokePathNV (GLuint path, GLint reference, GLuint mask, GLenum coverMode);
|
||||
GLAPI void APIENTRY glStencilThenCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
|
||||
GLAPI void APIENTRY glStencilThenCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
|
||||
GLAPI GLenum APIENTRY glPathGlyphIndexRangeNV (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]);
|
||||
GLAPI GLenum APIENTRY glPathGlyphIndexRangeNV (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint *baseAndCount);
|
||||
GLAPI GLenum APIENTRY glPathGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
|
||||
GLAPI GLenum APIENTRY glPathMemoryGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
|
||||
GLAPI void APIENTRY glProgramPathFragmentInputGenNV (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs);
|
||||
@@ -11364,6 +11459,10 @@ GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id);
|
||||
#endif
|
||||
#endif /* GL_NV_transform_feedback2 */
|
||||
|
||||
#ifndef GL_NV_uniform_buffer_std430_layout
|
||||
#define GL_NV_uniform_buffer_std430_layout 1
|
||||
#endif /* GL_NV_uniform_buffer_std430_layout */
|
||||
|
||||
#ifndef GL_NV_uniform_buffer_unified_memory
|
||||
#define GL_NV_uniform_buffer_unified_memory 1
|
||||
#define GL_UNIFORM_BUFFER_UNIFIED_NV 0x936E
|
||||
@@ -11765,54 +11864,6 @@ GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GL
|
||||
#ifndef GL_NV_vertex_program4
|
||||
#define GL_NV_vertex_program4 1
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x);
|
||||
GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y);
|
||||
GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z);
|
||||
GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w);
|
||||
GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x);
|
||||
GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y);
|
||||
GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z);
|
||||
GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
|
||||
GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v);
|
||||
GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v);
|
||||
GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
|
||||
GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params);
|
||||
#endif
|
||||
#endif /* GL_NV_vertex_program4 */
|
||||
|
||||
#ifndef GL_NV_video_capture
|
||||
|
||||
Vendored
+24
-3
@@ -153,6 +153,20 @@ typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
/*
|
||||
* To support platform where unsigned long cannot be used interchangeably with
|
||||
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
|
||||
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
|
||||
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
|
||||
* unsigned long long or similar (this results in different C++ name mangling).
|
||||
* To avoid changes for existing platforms, we restrict usage of intptr_t to
|
||||
* platforms where the size of a pointer is larger than the size of long.
|
||||
*/
|
||||
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
|
||||
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
|
||||
#define KHRONOS_USE_INTPTR_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
@@ -235,14 +249,21 @@ typedef unsigned short int khronos_uint16_t;
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
#ifdef KHRONOS_USE_INTPTR_T
|
||||
typedef intptr_t khronos_intptr_t;
|
||||
typedef uintptr_t khronos_uintptr_t;
|
||||
#elif defined(_WIN64)
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
Vendored
+1
-1
@@ -20,7 +20,7 @@ extern "C" {
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define WGL_WGLEXT_VERSION 20200813
|
||||
#define WGL_WGLEXT_VERSION 20231018
|
||||
|
||||
/* Generated C header for:
|
||||
* API: wgl
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
add_files(
|
||||
openttd_social_integration_api.h
|
||||
openttd_social_integration_api_v1.h
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
Copyright 2024 OpenTTD project
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2024 OpenTTD project
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Although all the source-files created by OpenTTD are licensed under the
|
||||
* GPL-v2, this file is an exception. This file is part of the API for
|
||||
* social integration plugins, and licensed under the MIT license, to allow
|
||||
* for non-free implementations.
|
||||
*/
|
||||
|
||||
/** @file openttd_social_integration_api.h Interface definitions for plugins to report/respond to social integration. */
|
||||
|
||||
#ifndef OPENTTD_SOCIAL_INTEGRATION_API_H
|
||||
#define OPENTTD_SOCIAL_INTEGRATION_API_H
|
||||
|
||||
#include "openttd_social_integration_api_v1.h"
|
||||
|
||||
#endif /* OPENTTD_SOCIAL_INTEGRATION_API_H */
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2024 OpenTTD project
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Although all the source-files created by OpenTTD are licensed under the
|
||||
* GPL-v2, this file is an exception. This file is part of the API for
|
||||
* social integration plugins, and licensed under the MIT license, to allow
|
||||
* for non-free implementations.
|
||||
*/
|
||||
|
||||
/** @file v1.h Version 1 definition of the OpenTTD Social Integration Plugin API. */
|
||||
|
||||
#ifndef OPENTTD_SOCIAL_INTEGRATION_API_V1_H
|
||||
#define OPENTTD_SOCIAL_INTEGRATION_API_V1_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Pointers supplied by the plugin for OpenTTD to use. */
|
||||
struct OpenTTD_SocialIntegration_v1_PluginInfo {
|
||||
/**
|
||||
* The Social Platform this plugin is for.
|
||||
*
|
||||
* UTF-8, nul-terminated. The plugin is and remains the owner of the memory.
|
||||
*
|
||||
* As there can only be one plugin active for each Social Platform, this
|
||||
* value is used to determine which plugin to use.
|
||||
*
|
||||
* A complete list of names can be found here:
|
||||
* https://wiki.openttd.org/en/Development/Social%20Integration
|
||||
*
|
||||
* Please use names from that list, including capitalization.
|
||||
*
|
||||
* If you create a plugin for a new Social Platform, please add it to the
|
||||
* wiki page.
|
||||
*/
|
||||
const char *social_platform;
|
||||
|
||||
const char *name; ///< Full name of the plugin. UTF-8, nul-terminated. The plugin is and remains the owner of the memory.
|
||||
const char *version; ///< Version of the plugin. UTF-8, nul-terminated. The plugin is and remains the owner of the memory.
|
||||
};
|
||||
|
||||
/** Pointers supplied by the plugin for OpenTTD to use. */
|
||||
struct OpenTTD_SocialIntegration_v1_PluginApi {
|
||||
/**
|
||||
* OpenTTD tells the plugin to shut down.
|
||||
*
|
||||
* The plugin should free any resources it allocated, and must not call any of the callback functions after this call.
|
||||
*/
|
||||
void (*shutdown)();
|
||||
|
||||
/**
|
||||
* OpenTTD calls this function at regular intervals, to handle any callbacks the plugin might have.
|
||||
*
|
||||
* It is also safe to call the OpenTTD_SocialIntegrationCallbacks functions here.
|
||||
*
|
||||
* @return True if the plugin wants to be called again, false if the plugin wants to be unloaded.
|
||||
*/
|
||||
bool (*run_callbacks)();
|
||||
|
||||
/**
|
||||
* The player has entered the main menu.
|
||||
*/
|
||||
void (*event_enter_main_menu)();
|
||||
|
||||
/**
|
||||
* The player has entered the Scenario Editor.
|
||||
*
|
||||
* @param map_width The width of the map in tiles.
|
||||
* @param map_height The height of the map in tiles.
|
||||
*/
|
||||
void (*event_enter_scenario_editor)(unsigned int map_width, unsigned int map_height);
|
||||
|
||||
/**
|
||||
* The player has entered a singleplayer game.
|
||||
*
|
||||
* @param map_width The width of the map in tiles.
|
||||
* @param map_height The height of the map in tiles.
|
||||
*/
|
||||
void (*event_enter_singleplayer)(unsigned int map_width, unsigned int map_height);
|
||||
|
||||
/**
|
||||
* The player has entered a multiplayer game.
|
||||
*
|
||||
* @param map_width The width of the map in tiles.
|
||||
* @param map_height The height of the map in tiles.
|
||||
*/
|
||||
void (*event_enter_multiplayer)(unsigned int map_width, unsigned int map_height);
|
||||
|
||||
/**
|
||||
* The player is joining a multiplayer game.
|
||||
*
|
||||
* This is followed by event_enter_multiplayer() if the join was successful.
|
||||
*/
|
||||
void (*event_joining_multiplayer)();
|
||||
};
|
||||
|
||||
/** Pointers supplied by OpenTTD, for the plugin to use. */
|
||||
struct OpenTTD_SocialIntegration_v1_OpenTTDInfo {
|
||||
const char *openttd_version; ///< Version of OpenTTD. UTF-8, nul-terminated. OpenTTD is and remains the owner of the memory.
|
||||
};
|
||||
|
||||
/** The result of the initialization. */
|
||||
enum OpenTTD_SocialIntegration_v1_InitResult : int {
|
||||
OTTD_SOCIAL_INTEGRATION_V1_INIT_SUCCESS = 1, ///< Plugin initialized successfully.
|
||||
OTTD_SOCIAL_INTEGRATION_V1_INIT_FAILED = -1, ///< Plugin failed to initialize (generic error).
|
||||
OTTD_SOCIAL_INTEGRATION_V1_INIT_PLATFORM_NOT_RUNNING = -2, ///< The Social Platform is not running.
|
||||
};
|
||||
|
||||
/**
|
||||
* Type of the Init function the plugin is expected to export from its dynamic library.
|
||||
*
|
||||
* The plugin has to export the implementation of this function as "SocialIntegration_vN_Init", where N is the API version this entry point is for.
|
||||
* A single plugin can have multiple versions implemented.
|
||||
*
|
||||
* @param[out] plugin_api Structure the plugin must fill with pointers. Can contain nullptr if the plugin does not support a feature. The plugin is owner of the memory.
|
||||
* @param[in] openttd_info Structure that OpenTTD filled with pointers. All pointers will remain valid until shutdown(). OpenTTD is owner of the memory.
|
||||
* @return The status of the initialization.
|
||||
*/
|
||||
typedef OpenTTD_SocialIntegration_v1_InitResult (*OpenTTD_SocialIntegration_v1_Init)(OpenTTD_SocialIntegration_v1_PluginApi *plugin_api, const OpenTTD_SocialIntegration_v1_OpenTTDInfo *openttd_info);
|
||||
|
||||
/**
|
||||
* Type of the GetInfo function the plugin is expected to export from its dynamic library.
|
||||
*
|
||||
* The plugin has to export the implementation of this function as "SocialIntegration_vN_GetInfo", where N is the API version this entry point is for.
|
||||
* A single plugin can have multiple versions implemented.
|
||||
*
|
||||
* @param[out] plugin_info Structure the plugin must fill with pointers. The plugin is owner of the memory.
|
||||
*/
|
||||
typedef void (*OpenTTD_SocialIntegration_v1_GetInfo)(OpenTTD_SocialIntegration_v1_PluginInfo *plugin_info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* OPENTTD_SOCIAL_INTEGRATION_API_V1_H */
|
||||
-2
@@ -18,8 +18,6 @@ SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* t
|
||||
SQInteger sqstd_rex_getsubexpcount(SQRex* exp);
|
||||
SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp);
|
||||
|
||||
SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output);
|
||||
|
||||
SQRESULT sqstd_register_stringlib(HSQUIRRELVM v);
|
||||
|
||||
#endif /*_SQSTD_STRING_H_*/
|
||||
|
||||
+18
-7
@@ -32,9 +32,9 @@
|
||||
|
||||
#include "../../../string_type.h"
|
||||
|
||||
typedef __int64 SQInteger;
|
||||
typedef unsigned __int64 SQUnsignedInteger;
|
||||
typedef unsigned __int64 SQHash; /*should be the same size of a pointer*/
|
||||
typedef int64_t SQInteger;
|
||||
typedef uint64_t SQUnsignedInteger;
|
||||
typedef uint64_t SQHash; /*should be the same size of a pointer*/
|
||||
typedef int SQInt32;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ typedef double SQFloat;
|
||||
typedef float SQFloat;
|
||||
#endif
|
||||
|
||||
typedef __int64 SQRawObjectVal; //must be 64bits
|
||||
typedef int64_t SQRawObjectVal; //must be 64bits
|
||||
#define SQ_OBJECT_RAWINIT() { _unVal.raw = 0; }
|
||||
|
||||
typedef void* SQUserPointer;
|
||||
@@ -174,12 +174,12 @@ typedef SQObject HSQOBJECT;
|
||||
typedef SQInteger (*SQFUNCTION)(HSQUIRRELVM);
|
||||
typedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size);
|
||||
typedef void (*SQCOMPILERERROR)(HSQUIRRELVM,const SQChar * /*desc*/,const SQChar * /*source*/,SQInteger /*line*/,SQInteger /*column*/);
|
||||
typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const SQChar * ,...);
|
||||
typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const std::string &);
|
||||
|
||||
typedef SQInteger (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,SQInteger);
|
||||
typedef SQInteger (*SQREADFUNC)(SQUserPointer,SQUserPointer,SQInteger);
|
||||
|
||||
typedef WChar (*SQLEXREADFUNC)(SQUserPointer);
|
||||
typedef char32_t (*SQLEXREADFUNC)(SQUserPointer);
|
||||
|
||||
typedef struct tagSQRegFunction{
|
||||
const SQChar *name;
|
||||
@@ -238,6 +238,7 @@ void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars);
|
||||
SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask);
|
||||
SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx);
|
||||
void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len);
|
||||
inline void sq_pushstring(HSQUIRRELVM v, const std::string &str, SQInteger len = -1) { sq_pushstring(v, str.data(), len == -1 ? str.size() : len); }
|
||||
void sq_pushfloat(HSQUIRRELVM v,SQFloat f);
|
||||
void sq_pushinteger(HSQUIRRELVM v,SQInteger n);
|
||||
void sq_pushbool(HSQUIRRELVM v,SQBool b);
|
||||
@@ -306,7 +307,8 @@ SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror,
|
||||
SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror);
|
||||
const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx);
|
||||
const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);
|
||||
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err);
|
||||
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err, SQInteger len = -1);
|
||||
inline SQRESULT sq_throwerror(HSQUIRRELVM v, const std::string_view err) { return sq_throwerror(v, err.data(), err.size()); }
|
||||
void sq_reseterror(HSQUIRRELVM v);
|
||||
void sq_getlasterror(HSQUIRRELVM v);
|
||||
|
||||
@@ -359,6 +361,15 @@ void sq_setdebughook(HSQUIRRELVM v);
|
||||
#define sq_isweakref(o) ((o)._type==OT_WEAKREF)
|
||||
#define sq_type(o) ((o)._type)
|
||||
|
||||
/* Limit the total number of ops that can be consumed by an operation */
|
||||
struct SQOpsLimiter {
|
||||
SQOpsLimiter(HSQUIRRELVM v, SQInteger ops, const char *label);
|
||||
~SQOpsLimiter();
|
||||
private:
|
||||
HSQUIRRELVM _v;
|
||||
SQInteger _ops;
|
||||
};
|
||||
|
||||
/* deprecated */
|
||||
#define sq_createslot(v,n) sq_newslot(v,n,SQFalse)
|
||||
|
||||
|
||||
+20
-19
@@ -5,6 +5,7 @@
|
||||
#include <squirrel.h>
|
||||
#include <sqstdaux.h>
|
||||
|
||||
#include "../../fmt/format.h"
|
||||
#include "../../../safeguards.h"
|
||||
|
||||
void sqstd_printcallstack(HSQUIRRELVM v)
|
||||
@@ -38,7 +39,7 @@ void sqstd_printcallstack(HSQUIRRELVM v)
|
||||
src = si.source;
|
||||
}
|
||||
}
|
||||
pf(v,"*FUNCTION [%s()] %s line [" OTTD_PRINTF64 "]\n",fn,src,si.line);
|
||||
pf(v,fmt::format("*FUNCTION [{}()] {} line [{}]\n",fn,src,si.line));
|
||||
level++;
|
||||
}
|
||||
level=0;
|
||||
@@ -52,56 +53,56 @@ void sqstd_printcallstack(HSQUIRRELVM v)
|
||||
switch(sq_gettype(v,-1))
|
||||
{
|
||||
case OT_NULL:
|
||||
pf(v,"[%s] NULL\n",name);
|
||||
pf(v,fmt::format("[{}] NULL\n",name));
|
||||
break;
|
||||
case OT_INTEGER:
|
||||
sq_getinteger(v,-1,&i);
|
||||
pf(v,"[%s] " OTTD_PRINTF64 "\n",name,i);
|
||||
pf(v,fmt::format("[{}] {}\n",name,i));
|
||||
break;
|
||||
case OT_FLOAT:
|
||||
sq_getfloat(v,-1,&f);
|
||||
pf(v,"[%s] %.14g\n",name,f);
|
||||
pf(v,fmt::format("[{}] {:14g}\n",name,f));
|
||||
break;
|
||||
case OT_USERPOINTER:
|
||||
pf(v,"[%s] USERPOINTER\n",name);
|
||||
pf(v,fmt::format("[{}] USERPOINTER\n",name));
|
||||
break;
|
||||
case OT_STRING:
|
||||
sq_getstring(v,-1,&s);
|
||||
pf(v,"[%s] \"%s\"\n",name,s);
|
||||
pf(v,fmt::format("[{}] \"{}\"\n",name,s));
|
||||
break;
|
||||
case OT_TABLE:
|
||||
pf(v,"[%s] TABLE\n",name);
|
||||
pf(v,fmt::format("[{}] TABLE\n",name));
|
||||
break;
|
||||
case OT_ARRAY:
|
||||
pf(v,"[%s] ARRAY\n",name);
|
||||
pf(v,fmt::format("[{}] ARRAY\n",name));
|
||||
break;
|
||||
case OT_CLOSURE:
|
||||
pf(v,"[%s] CLOSURE\n",name);
|
||||
pf(v,fmt::format("[{}] CLOSURE\n",name));
|
||||
break;
|
||||
case OT_NATIVECLOSURE:
|
||||
pf(v,"[%s] NATIVECLOSURE\n",name);
|
||||
pf(v,fmt::format("[{}] NATIVECLOSURE\n",name));
|
||||
break;
|
||||
case OT_GENERATOR:
|
||||
pf(v,"[%s] GENERATOR\n",name);
|
||||
pf(v,fmt::format("[{}] GENERATOR\n",name));
|
||||
break;
|
||||
case OT_USERDATA:
|
||||
pf(v,"[%s] USERDATA\n",name);
|
||||
pf(v,fmt::format("[{}] USERDATA\n",name));
|
||||
break;
|
||||
case OT_THREAD:
|
||||
pf(v,"[%s] THREAD\n",name);
|
||||
pf(v,fmt::format("[{}] THREAD\n",name));
|
||||
break;
|
||||
case OT_CLASS:
|
||||
pf(v,"[%s] CLASS\n",name);
|
||||
pf(v,fmt::format("[{}] CLASS\n",name));
|
||||
break;
|
||||
case OT_INSTANCE:
|
||||
pf(v,"[%s] INSTANCE\n",name);
|
||||
pf(v,fmt::format("[{}] INSTANCE\n",name));
|
||||
break;
|
||||
case OT_WEAKREF:
|
||||
pf(v,"[%s] WEAKREF\n",name);
|
||||
pf(v,fmt::format("[{}] WEAKREF\n",name));
|
||||
break;
|
||||
case OT_BOOL:{
|
||||
sq_getbool(v,-1,&b);
|
||||
pf(v,"[%s] %s\n",name,b?"true":"false");
|
||||
pf(v,fmt::format("[{}] {}\n",name,b?"true":"false"));
|
||||
}
|
||||
break;
|
||||
default: assert(0); break;
|
||||
@@ -119,7 +120,7 @@ static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v)
|
||||
const SQChar *sErr = nullptr;
|
||||
if(sq_gettop(v)>=1) {
|
||||
if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr))) {
|
||||
pf(v,"\nAN ERROR HAS OCCURRED [%s]\n",sErr);
|
||||
pf(v,fmt::format("\nAN ERROR HAS OCCURRED [{}]\n",sErr));
|
||||
}
|
||||
else{
|
||||
pf(v,"\nAN ERROR HAS OCCURRED [unknown]\n");
|
||||
@@ -134,7 +135,7 @@ void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSourc
|
||||
{
|
||||
SQPRINTFUNCTION pf = sq_getprintfunc(v);
|
||||
if(pf) {
|
||||
pf(v,"%s line = (" OTTD_PRINTF64 ") column = (" OTTD_PRINTF64 ") : error %s\n",sSource,line,column,sErr);
|
||||
pf(v,fmt::format("{} line = ({}) column = ({}) : error {}\n",sSource,line,column,sErr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ static SQRegFunction mathlib_funcs[] = {
|
||||
_DECL_FUNC(exp,2,".n"),
|
||||
#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS
|
||||
_DECL_FUNC(srand,2,".n"),
|
||||
_DECL_FUNC(rand,1,NULL),
|
||||
_DECL_FUNC(rand,1,nullptr),
|
||||
#endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */
|
||||
_DECL_FUNC(fabs,2,".n"),
|
||||
_DECL_FUNC(abs,2,".n"),
|
||||
|
||||
+26
-26
@@ -378,8 +378,8 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar
|
||||
SQRexNodeType type = node->type;
|
||||
switch(type) {
|
||||
case OP_GREEDY: {
|
||||
//SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
|
||||
SQRexNode *greedystop = NULL;
|
||||
//SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : nullptr;
|
||||
SQRexNode *greedystop = nullptr;
|
||||
SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
|
||||
const SQChar *s=str, *good = str;
|
||||
|
||||
@@ -403,7 +403,7 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar
|
||||
if(greedystop->type != OP_GREEDY ||
|
||||
(greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
|
||||
{
|
||||
SQRexNode *gnext = NULL;
|
||||
SQRexNode *gnext = nullptr;
|
||||
if(greedystop->next != -1) {
|
||||
gnext = &exp->_nodes[greedystop->next];
|
||||
}else if(next && next->next != -1){
|
||||
@@ -425,12 +425,12 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar
|
||||
if(p0 == p1 && p0 == nmaches) return good;
|
||||
else if(nmaches >= p0 && p1 == 0xFFFF) return good;
|
||||
else if(nmaches >= p0 && nmaches <= p1) return good;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
case OP_OR: {
|
||||
const SQChar *asd = str;
|
||||
SQRexNode *temp=&exp->_nodes[node->left];
|
||||
while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {
|
||||
while( (asd = sqstd_rex_matchnode(exp,temp,asd,nullptr)) ) {
|
||||
if(temp->next != -1)
|
||||
temp = &exp->_nodes[temp->next];
|
||||
else
|
||||
@@ -438,13 +438,13 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar
|
||||
}
|
||||
asd = str;
|
||||
temp = &exp->_nodes[node->right];
|
||||
while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {
|
||||
while( (asd = sqstd_rex_matchnode(exp,temp,asd,nullptr)) ) {
|
||||
if(temp->next != -1)
|
||||
temp = &exp->_nodes[temp->next];
|
||||
else
|
||||
return asd;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
case OP_EXPR:
|
||||
@@ -459,7 +459,7 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar
|
||||
}
|
||||
|
||||
do {
|
||||
SQRexNode *subnext = NULL;
|
||||
SQRexNode *subnext = nullptr;
|
||||
if(n->next != -1) {
|
||||
subnext = &exp->_nodes[n->next];
|
||||
}else {
|
||||
@@ -470,7 +470,7 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar
|
||||
exp->_matches[capture].begin = 0;
|
||||
exp->_matches[capture].len = 0;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
} while((n->next != -1) && (n = &exp->_nodes[n->next]));
|
||||
|
||||
@@ -483,15 +483,15 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar
|
||||
|| (str == exp->_eol && !isspace(*(str-1)))
|
||||
|| (!isspace(*str) && isspace(*(str+1)))
|
||||
|| (isspace(*str) && !isspace(*(str+1))) ) {
|
||||
return (node->left == 'b')?str:NULL;
|
||||
return (node->left == 'b')?str:nullptr;
|
||||
}
|
||||
return (node->left == 'b')?NULL:str;
|
||||
return (node->left == 'b')?nullptr:str;
|
||||
case OP_BOL:
|
||||
if(str == exp->_bol) return str;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
case OP_EOL:
|
||||
if(str == exp->_eol) return str;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
case OP_DOT:{
|
||||
*str++;
|
||||
}
|
||||
@@ -502,26 +502,26 @@ static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar
|
||||
*str++;
|
||||
return str;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
case OP_CCLASS:
|
||||
if(sqstd_rex_matchcclass(node->left,*str)) {
|
||||
*str++;
|
||||
return str;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
default: /* char */
|
||||
if(*str != (SQChar)node->type) return NULL;
|
||||
if(*str != (SQChar)node->type) return nullptr;
|
||||
*str++;
|
||||
return str;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* public api */
|
||||
SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)
|
||||
{
|
||||
SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex));
|
||||
exp->_eol = exp->_bol = NULL;
|
||||
exp->_eol = exp->_bol = nullptr;
|
||||
exp->_p = pattern;
|
||||
exp->_nallocated = (SQInteger)strlen(pattern) * sizeof(SQChar);
|
||||
exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode));
|
||||
@@ -558,7 +558,7 @@ SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)
|
||||
}
|
||||
catch (...) {
|
||||
sqstd_rex_free(exp);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return exp;
|
||||
}
|
||||
@@ -574,19 +574,19 @@ void sqstd_rex_free(SQRex *exp)
|
||||
|
||||
SQBool sqstd_rex_match(SQRex* exp,const SQChar* text)
|
||||
{
|
||||
const SQChar* res = NULL;
|
||||
const SQChar* res = nullptr;
|
||||
exp->_bol = text;
|
||||
exp->_eol = text + strlen(text);
|
||||
exp->_currsubexp = 0;
|
||||
res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL);
|
||||
if(res == NULL || res != exp->_eol)
|
||||
res = sqstd_rex_matchnode(exp,exp->_nodes,text,nullptr);
|
||||
if(res == nullptr || res != exp->_eol)
|
||||
return SQFalse;
|
||||
return SQTrue;
|
||||
}
|
||||
|
||||
SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end)
|
||||
{
|
||||
const SQChar *cur = NULL;
|
||||
const SQChar *cur = nullptr;
|
||||
SQInteger node = exp->_first;
|
||||
if(text_begin >= text_end) return SQFalse;
|
||||
exp->_bol = text_begin;
|
||||
@@ -595,15 +595,15 @@ SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* t
|
||||
cur = text_begin;
|
||||
while(node != -1) {
|
||||
exp->_currsubexp = 0;
|
||||
cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL);
|
||||
cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,nullptr);
|
||||
if(!cur)
|
||||
break;
|
||||
node = exp->_nodes[node].next;
|
||||
}
|
||||
*text_begin++;
|
||||
} while(cur == NULL && text_begin != text_end);
|
||||
} while(cur == nullptr && text_begin != text_end);
|
||||
|
||||
if(cur == NULL)
|
||||
if(cur == nullptr)
|
||||
return SQFalse;
|
||||
|
||||
--text_begin;
|
||||
|
||||
+3
-99
@@ -1,7 +1,6 @@
|
||||
/* see copyright notice in squirrel.h */
|
||||
#include <squirrel.h>
|
||||
#include <sqstdstring.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define scstrchr strchr
|
||||
#define scatoi atoi
|
||||
@@ -53,101 +52,6 @@ static SQInteger validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src,
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Little hack to remove the "format not a string literal, argument types not checked" warning.
|
||||
* This check has been added to OpenTTD to make sure that nobody passes wrong string literals,
|
||||
* but three lines in Squirrel have a little problem with those. Therefor we use this hack
|
||||
* which basically uses vsnprintf instead of sprintf as vsnprintf is not testing for the right
|
||||
* string literal at compile time.
|
||||
*/
|
||||
static void _append_string(SQInteger &i, SQChar *dest, SQInteger allocated, const SQChar *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
i += vsnprintf(&dest[i],allocated-i,fmt,va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
|
||||
SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output)
|
||||
{
|
||||
const SQChar *format;
|
||||
SQChar *dest;
|
||||
SQChar fmt[MAX_FORMAT_LEN];
|
||||
sq_getstring(v,nformatstringidx,&format);
|
||||
SQInteger allocated = (sq_getsize(v,nformatstringidx)+2)*sizeof(SQChar);
|
||||
dest = sq_getscratchpad(v,allocated);
|
||||
SQInteger n = 0,i = 0, nparam = nformatstringidx+1, w = 0;
|
||||
while(format[n] != '\0') {
|
||||
if(format[n] != '%') {
|
||||
assert(i < allocated);
|
||||
dest[i++] = format[n];
|
||||
n++;
|
||||
}
|
||||
else if(format[n+1] == '%') { //handles %%
|
||||
dest[i++] = '%';
|
||||
n += 2;
|
||||
}
|
||||
else {
|
||||
n++;
|
||||
if( nparam > sq_gettop(v) )
|
||||
return sq_throwerror(v,"not enough paramters for the given format string");
|
||||
n = validate_format(v,fmt,format,n,w);
|
||||
if(n < 0) return -1;
|
||||
SQInteger addlen = 0;
|
||||
SQInteger valtype = 0;
|
||||
const SQChar *ts;
|
||||
SQInteger ti;
|
||||
SQFloat tf;
|
||||
switch(format[n]) {
|
||||
case 's':
|
||||
if(SQ_FAILED(sq_getstring(v,nparam,&ts)))
|
||||
return sq_throwerror(v,"string expected for the specified format");
|
||||
addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar));
|
||||
valtype = 's';
|
||||
break;
|
||||
case 'i': case 'd': case 'c':case 'o': case 'u': case 'x': case 'X':
|
||||
if(SQ_FAILED(sq_getinteger(v,nparam,&ti)))
|
||||
return sq_throwerror(v,"integer expected for the specified format");
|
||||
addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar));
|
||||
valtype = 'i';
|
||||
break;
|
||||
case 'f': case 'g': case 'G': case 'e': case 'E':
|
||||
if(SQ_FAILED(sq_getfloat(v,nparam,&tf)))
|
||||
return sq_throwerror(v,"float expected for the specified format");
|
||||
addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar));
|
||||
valtype = 'f';
|
||||
break;
|
||||
default:
|
||||
return sq_throwerror(v,"invalid format");
|
||||
}
|
||||
n++;
|
||||
allocated += addlen + sizeof(SQChar);
|
||||
dest = sq_getscratchpad(v,allocated);
|
||||
switch(valtype) {
|
||||
case 's': _append_string(i,dest,allocated,fmt,ts); break;
|
||||
case 'i': _append_string(i,dest,allocated,fmt,ti); break;
|
||||
case 'f': _append_string(i,dest,allocated,fmt,tf); break;
|
||||
};
|
||||
nparam ++;
|
||||
}
|
||||
}
|
||||
*outlen = i;
|
||||
dest[i] = '\0';
|
||||
*output = dest;
|
||||
return SQ_OK;
|
||||
}
|
||||
|
||||
static SQInteger _string_format(HSQUIRRELVM v)
|
||||
{
|
||||
SQChar *dest = NULL;
|
||||
SQInteger length = 0;
|
||||
if(SQ_FAILED(sqstd_format(v,2,&length,&dest)))
|
||||
return -1;
|
||||
sq_pushstring(v,dest,length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __strip_l(const SQChar *str,const SQChar **start)
|
||||
{
|
||||
const SQChar *t = str;
|
||||
@@ -208,16 +112,16 @@ static SQInteger _string_split(HSQUIRRELVM v)
|
||||
memcpy(stemp,str,memsize);
|
||||
tok = scstrtok(stemp,seps);
|
||||
sq_newarray(v,0);
|
||||
while( tok != NULL ) {
|
||||
while( tok != nullptr ) {
|
||||
sq_pushstring(v,tok,-1);
|
||||
sq_arrayappend(v,-2);
|
||||
tok = scstrtok( NULL, seps );
|
||||
tok = scstrtok( nullptr, seps );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define SETUP_REX(v) \
|
||||
SQRex *self = NULL; \
|
||||
SQRex *self = nullptr; \
|
||||
sq_getinstanceup(v,1,(SQUserPointer *)&self,0);
|
||||
|
||||
static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger size)
|
||||
|
||||
+21
-9
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include "../../../stdafx.h"
|
||||
#include "../../fmt/format.h"
|
||||
|
||||
#include <squirrel.h>
|
||||
#include "sqpcheader.h"
|
||||
@@ -26,7 +27,7 @@ bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPt
|
||||
*o = &stack_get(v,idx);
|
||||
if(type(**o) != type){
|
||||
SQObjectPtr oval = v->PrintObjVal(**o);
|
||||
v->Raise_Error("wrong argument type, expected '%s' got '%.50s'",IdType2Name(type),_stringval(oval));
|
||||
v->Raise_Error(fmt::format("wrong argument type, expected '{}' got '{:.50s}'",IdType2Name(type),_stringval(oval)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -47,9 +48,7 @@ SQInteger sq_aux_throwobject(HSQUIRRELVM v,SQObjectPtr &e)
|
||||
|
||||
SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type)
|
||||
{
|
||||
char buf[100];
|
||||
seprintf(buf, lastof(buf), "unexpected type %s", IdType2Name(type));
|
||||
return sq_throwerror(v, buf);
|
||||
return sq_throwerror(v, fmt::format("unexpected type {}", IdType2Name(type)));
|
||||
}
|
||||
|
||||
HSQUIRRELVM sq_open(SQInteger initialstacksize)
|
||||
@@ -932,9 +931,9 @@ void sq_resetobject(HSQOBJECT *po)
|
||||
po->_unVal.pUserPointer=nullptr;po->_type=OT_NULL;
|
||||
}
|
||||
|
||||
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err)
|
||||
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err, SQInteger len)
|
||||
{
|
||||
v->_lasterror=SQString::Create(_ss(v),err);
|
||||
v->_lasterror=SQString::Create(_ss(v),err, len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1260,9 +1259,9 @@ struct BufState{
|
||||
SQInteger size;
|
||||
};
|
||||
|
||||
WChar buf_lexfeed(SQUserPointer file)
|
||||
char32_t buf_lexfeed(SQUserPointer file)
|
||||
{
|
||||
/* Convert an UTF-8 character into a WChar */
|
||||
/* Convert an UTF-8 character into a char32_t */
|
||||
BufState *buf = (BufState *)file;
|
||||
const char *p = &buf->buf[buf->ptr];
|
||||
|
||||
@@ -1280,7 +1279,7 @@ WChar buf_lexfeed(SQUserPointer file)
|
||||
buf->ptr += len;
|
||||
|
||||
/* Convert the character, and when definitely invalid, bail out as well. */
|
||||
WChar c;
|
||||
char32_t c;
|
||||
if (Utf8Decode(&c, p) != len) return -1;
|
||||
|
||||
return c;
|
||||
@@ -1324,3 +1323,16 @@ void sq_free(void *p,SQUnsignedInteger size)
|
||||
SQ_FREE(p,size);
|
||||
}
|
||||
|
||||
SQOpsLimiter::SQOpsLimiter(HSQUIRRELVM v, SQInteger ops, const char *label) : _v(v)
|
||||
{
|
||||
this->_ops = v->_ops_till_suspend_error_threshold;
|
||||
if (this->_ops == INT64_MIN) {
|
||||
v->_ops_till_suspend_error_threshold = v->_ops_till_suspend - ops;
|
||||
v->_ops_till_suspend_error_label = label;
|
||||
}
|
||||
}
|
||||
|
||||
SQOpsLimiter::~SQOpsLimiter()
|
||||
{
|
||||
this->_v->_ops_till_suspend_error_threshold = this->_ops;
|
||||
}
|
||||
|
||||
+16
-16
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include "../../../stdafx.h"
|
||||
#include "../../fmt/format.h"
|
||||
|
||||
#include "sqpcheader.h"
|
||||
#include "sqvm.h"
|
||||
@@ -12,7 +13,6 @@
|
||||
#include "sqfuncproto.h"
|
||||
#include "sqclosure.h"
|
||||
#include "sqclass.h"
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../../../safeguards.h"
|
||||
@@ -101,7 +101,7 @@ static SQInteger base_getstackinfos(HSQUIRRELVM v)
|
||||
SQInteger level;
|
||||
SQStackInfos si;
|
||||
SQInteger seq = 0;
|
||||
const SQChar *name = NULL;
|
||||
const SQChar *name = nullptr;
|
||||
sq_getinteger(v, -1, &level);
|
||||
if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si)))
|
||||
{
|
||||
@@ -172,7 +172,7 @@ static SQInteger base_print(HSQUIRRELVM v)
|
||||
const SQChar *str;
|
||||
sq_tostring(v,2);
|
||||
sq_getstring(v,-1,&str);
|
||||
if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,"%s",str);
|
||||
if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ static SQInteger base_print(HSQUIRRELVM v)
|
||||
static SQInteger base_compilestring(HSQUIRRELVM v)
|
||||
{
|
||||
SQInteger nargs=sq_gettop(v);
|
||||
const SQChar *src=NULL,*name="unnamedbuffer";
|
||||
const SQChar *src=nullptr,*name="unnamedbuffer";
|
||||
SQInteger size;
|
||||
sq_getstring(v,2,&src);
|
||||
size=sq_getsize(v,2);
|
||||
@@ -214,7 +214,7 @@ static SQInteger base_array(HSQUIRRELVM v)
|
||||
SQInteger nInitialSize = tointeger(stack_get(v,2));
|
||||
SQInteger ret = 1;
|
||||
if (nInitialSize < 0) {
|
||||
v->Raise_Error("can't create/resize array with/to size " OTTD_PRINTF64, nInitialSize);
|
||||
v->Raise_Error(fmt::format("can't create/resize array with/to size {}", nInitialSize));
|
||||
nInitialSize = 0;
|
||||
ret = -1;
|
||||
}
|
||||
@@ -239,26 +239,26 @@ static SQInteger base_type(HSQUIRRELVM v)
|
||||
static SQRegFunction base_funcs[]={
|
||||
//generic
|
||||
#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS
|
||||
{"seterrorhandler",base_seterrorhandler,2, NULL},
|
||||
{"setdebughook",base_setdebughook,2, NULL},
|
||||
{"enabledebuginfo",base_enabledebuginfo,2, NULL},
|
||||
{"seterrorhandler",base_seterrorhandler,2, nullptr},
|
||||
{"setdebughook",base_setdebughook,2, nullptr},
|
||||
{"enabledebuginfo",base_enabledebuginfo,2, nullptr},
|
||||
{"getstackinfos",base_getstackinfos,2, ".n"},
|
||||
{"getroottable",base_getroottable,1, NULL},
|
||||
{"setroottable",base_setroottable,2, NULL},
|
||||
{"getconsttable",base_getconsttable,1, NULL},
|
||||
{"setconsttable",base_setconsttable,2, NULL},
|
||||
{"getroottable",base_getroottable,1, nullptr},
|
||||
{"setroottable",base_setroottable,2, nullptr},
|
||||
{"getconsttable",base_getconsttable,1, nullptr},
|
||||
{"setconsttable",base_setconsttable,2, nullptr},
|
||||
#endif
|
||||
{"assert",base_assert,2, nullptr},
|
||||
{"print",base_print,2, nullptr},
|
||||
#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS
|
||||
{"compilestring",base_compilestring,-2, ".ss"},
|
||||
{"newthread",base_newthread,2, ".c"},
|
||||
{"suspend",base_suspend,-1, NULL},
|
||||
{"suspend",base_suspend,-1, nullptr},
|
||||
#endif
|
||||
{"array",base_array,-2, ".n"},
|
||||
{"type",base_type,2, nullptr},
|
||||
#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS
|
||||
{"dummy",base_dummy,0,NULL},
|
||||
{"dummy",base_dummy,0,nullptr},
|
||||
#ifndef NO_GARBAGE_COLLECTOR
|
||||
{"collectgarbage",base_collectgarbage,1, "t"},
|
||||
#endif
|
||||
@@ -559,7 +559,7 @@ bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bott
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func)
|
||||
bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger, SQInteger,SQInteger func)
|
||||
{
|
||||
SQArray *a = _array(arr);
|
||||
SQInteger i;
|
||||
@@ -763,7 +763,7 @@ static SQInteger closure_getinfos(HSQUIRRELVM v) {
|
||||
res->NewSlot(SQString::Create(_ss(v),"name",-1),nc->_name);
|
||||
res->NewSlot(SQString::Create(_ss(v),"paramscheck",-1),nc->_nparamscheck);
|
||||
SQObjectPtr typecheck;
|
||||
if(nc->_typecheck.size() > 0) {
|
||||
if(!nc->_typecheck.empty()) {
|
||||
typecheck =
|
||||
SQArray::Create(_ss(v), nc->_typecheck.size());
|
||||
for(SQUnsignedInteger n = 0; n<nc->_typecheck.size(); n++) {
|
||||
|
||||
+1
-1
@@ -187,7 +187,7 @@ SQInstance::~SQInstance()
|
||||
if(_class){ Finalize(); } //if _class is null it was already finalized by the GC
|
||||
}
|
||||
|
||||
bool SQInstance::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res)
|
||||
bool SQInstance::GetMetaMethod(SQVM *,SQMetaMethod mm,SQObjectPtr &res)
|
||||
{
|
||||
if(type(_class->_metamethods[mm]) != OT_NULL) {
|
||||
res = _class->_metamethods[mm];
|
||||
|
||||
+4
-3
@@ -10,6 +10,7 @@ struct SQClassMember {
|
||||
val = o.val;
|
||||
attrs = o.attrs;
|
||||
}
|
||||
SQClassMember& operator=(SQClassMember &o) = delete;
|
||||
SQObjectPtr val;
|
||||
SQObjectPtr attrs;
|
||||
};
|
||||
@@ -54,13 +55,13 @@ public:
|
||||
bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val);
|
||||
bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval);
|
||||
void Lock() { _locked = true; if(_base) _base->Lock(); }
|
||||
void Release() {
|
||||
void Release() override {
|
||||
if (_hook) { _hook(_typetag,0);}
|
||||
sq_delete(this, SQClass);
|
||||
}
|
||||
void Finalize();
|
||||
void Finalize() override;
|
||||
#ifndef NO_GARBAGE_COLLECTOR
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue);
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override;
|
||||
#endif
|
||||
SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);
|
||||
SQInstance *CreateInstance();
|
||||
|
||||
+9
-9
@@ -14,7 +14,7 @@ public:
|
||||
new (nc) SQClosure(ss,func);
|
||||
return nc;
|
||||
}
|
||||
void Release(){
|
||||
void Release() override {
|
||||
sq_delete(this,SQClosure);
|
||||
}
|
||||
SQClosure *Clone()
|
||||
@@ -32,8 +32,8 @@ public:
|
||||
bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write);
|
||||
static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret);
|
||||
#ifndef NO_GARBAGE_COLLECTOR
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue);
|
||||
void Finalize(){_outervalues.resize(0); }
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override;
|
||||
void Finalize() override {_outervalues.resize(0); }
|
||||
#endif
|
||||
SQObjectPtr _env;
|
||||
SQObjectPtr _function;
|
||||
@@ -60,14 +60,14 @@ public:
|
||||
_state=eDead;
|
||||
_stack.resize(0);
|
||||
_closure=_null_;}
|
||||
void Release(){
|
||||
void Release() override {
|
||||
sq_delete(this,SQGenerator);
|
||||
}
|
||||
bool Yield(SQVM *v);
|
||||
bool Resume(SQVM *v,SQInteger target);
|
||||
#ifndef NO_GARBAGE_COLLECTOR
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue);
|
||||
void Finalize(){_stack.resize(0);_closure=_null_;}
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override;
|
||||
void Finalize() override {_stack.resize(0);_closure=_null_;}
|
||||
#endif
|
||||
SQObjectPtr _closure;
|
||||
SQObjectPtrVec _stack;
|
||||
@@ -102,12 +102,12 @@ public:
|
||||
{
|
||||
REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
|
||||
}
|
||||
void Release(){
|
||||
void Release() override {
|
||||
sq_delete(this,SQNativeClosure);
|
||||
}
|
||||
#ifndef NO_GARBAGE_COLLECTOR
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue);
|
||||
void Finalize(){_outervalues.resize(0);}
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override;
|
||||
void Finalize() override {_outervalues.resize(0);}
|
||||
#endif
|
||||
SQInteger _nparamscheck;
|
||||
SQIntVec _typecheck;
|
||||
|
||||
+11
-29
@@ -3,10 +3,10 @@
|
||||
*/
|
||||
|
||||
#include "../../../stdafx.h"
|
||||
#include "../../fmt/format.h"
|
||||
|
||||
#include <squirrel.h>
|
||||
#include "sqpcheader.h"
|
||||
#include <stdarg.h>
|
||||
#include "sqopcodes.h"
|
||||
#include "sqstring.h"
|
||||
#include "sqfuncproto.h"
|
||||
@@ -57,24 +57,15 @@ typedef sqvector<ExpState> ExpStateVec;
|
||||
class SQCompiler
|
||||
{
|
||||
public:
|
||||
SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) : _token(0), _fs(nullptr), _lex(_ss(v), rg, up, ThrowError, this), _debugline(0), _debugop(0)
|
||||
SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) : _token(0), _fs(nullptr), _lex(_ss(v), rg, up), _debugline(0), _debugop(0)
|
||||
{
|
||||
_vm=v;
|
||||
_sourcename = SQString::Create(_ss(v), sourcename);
|
||||
_lineinfo = lineinfo;_raiseerror = raiseerror;
|
||||
}
|
||||
NORETURN static void ThrowError(void *ud, const SQChar *s) {
|
||||
SQCompiler *c = (SQCompiler *)ud;
|
||||
c->Error("%s", s);
|
||||
}
|
||||
NORETURN void Error(const SQChar *s, ...) WARN_FORMAT(2, 3)
|
||||
[[noreturn]] void Error(const std::string &msg)
|
||||
{
|
||||
static SQChar temp[256];
|
||||
va_list vl;
|
||||
va_start(vl, s);
|
||||
vseprintf(temp, lastof(temp), s, vl);
|
||||
va_end(vl);
|
||||
throw temp;
|
||||
throw CompileException(msg);
|
||||
}
|
||||
void Lex(){ _token = _lex.Lex();}
|
||||
void PushExpState(){ _expstates.push_back(ExpState()); }
|
||||
@@ -120,9 +111,9 @@ public:
|
||||
default:
|
||||
etypename = _lex.Tok2Str(tok);
|
||||
}
|
||||
Error("expected '%s'", etypename);
|
||||
Error(fmt::format("expected '{}'", etypename));
|
||||
}
|
||||
Error("expected '%c'", (char)tok);
|
||||
Error(fmt::format("expected '{:c}'", tok));
|
||||
}
|
||||
}
|
||||
SQObjectPtr ret;
|
||||
@@ -164,7 +155,7 @@ public:
|
||||
_debugline = 1;
|
||||
_debugop = 0;
|
||||
|
||||
SQFuncState funcstate(_ss(_vm), nullptr,ThrowError,this);
|
||||
SQFuncState funcstate(_ss(_vm), nullptr);
|
||||
funcstate._name = SQString::Create(_ss(_vm), "main");
|
||||
_fs = &funcstate;
|
||||
_fs->AddParameter(_fs->CreateString("this"));
|
||||
@@ -186,12 +177,12 @@ public:
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
catch (SQChar *compilererror) {
|
||||
catch (const CompileException &compilererror) {
|
||||
if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
|
||||
_ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):"unknown",
|
||||
_ss(_vm)->_compilererrorhandler(_vm, compilererror.what(), type(_sourcename) == OT_STRING ? _stringval(_sourcename) : "unknown",
|
||||
_lex._currentline, _lex._currentcolumn);
|
||||
}
|
||||
_vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1);
|
||||
_vm->_lasterror = SQString::Create(_ss(_vm), compilererror.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -607,7 +598,6 @@ public:
|
||||
switch(_token)
|
||||
{
|
||||
case TK_STRING_LITERAL: {
|
||||
//SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1));
|
||||
_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
|
||||
Lex();
|
||||
}
|
||||
@@ -648,7 +638,7 @@ public:
|
||||
Expect('.'); constid = Expect(TK_IDENTIFIER);
|
||||
if(!_table(constant)->Get(constid,constval)) {
|
||||
constval.Null();
|
||||
Error("invalid constant [%s.%s]", _stringval(id),_stringval(constid));
|
||||
Error(fmt::format("invalid constant [{}.{}]", _stringval(id),_stringval(constid)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -840,7 +830,6 @@ public:
|
||||
unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
|
||||
SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
|
||||
_fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val);
|
||||
//_fs->PopTarget();
|
||||
}
|
||||
if(separator == ',') //hack recognizes a table from the separator
|
||||
_fs->SetIntructionParam(tpos, 1, nkeys);
|
||||
@@ -1053,7 +1042,6 @@ public:
|
||||
if(tonextcondjmp != -1)
|
||||
_fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
|
||||
if(_token == TK_DEFAULT) {
|
||||
// _fs->AddLineInfos(_lex._currentline, _lineinfo);
|
||||
Lex(); Expect(':');
|
||||
SQInteger stacksize = _fs->GetStackSize();
|
||||
_last_stacksize = _fs->GetStackSize();
|
||||
@@ -1167,11 +1155,6 @@ public:
|
||||
}
|
||||
SQTable *enums = _table(_ss(_vm)->_consts);
|
||||
SQObjectPtr strongid = id;
|
||||
/*SQObjectPtr dummy;
|
||||
if(enums->Get(strongid,dummy)) {
|
||||
dummy.Null(); strongid.Null();
|
||||
Error("enumeration already exists");
|
||||
}*/
|
||||
enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
|
||||
strongid.Null();
|
||||
Lex();
|
||||
@@ -1318,7 +1301,6 @@ public:
|
||||
funcstate->AddLineInfos(_lex._prevtoken == '\n'?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
|
||||
funcstate->AddInstruction(_OP_RETURN, -1);
|
||||
funcstate->SetStackSize(0);
|
||||
//_fs->->_stacksize = _fs->_stacksize;
|
||||
SQFunctionProto *func = funcstate->BuildProto();
|
||||
#ifdef _DEBUG_DUMP
|
||||
funcstate->Dump(func);
|
||||
|
||||
+1
-6
@@ -71,12 +71,7 @@ struct SQVM;
|
||||
#define TK_ENUM 323
|
||||
#define TK_CONST 324
|
||||
|
||||
/* MSVC doesn't like NORETURN for function prototypes, but we kinda need it for GCC. */
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s);
|
||||
#else
|
||||
typedef NORETURN void(*CompilerErrorFunc)(void *ud, const SQChar *s);
|
||||
#endif
|
||||
using CompileException = std::runtime_error;
|
||||
|
||||
bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo);
|
||||
#endif //_SQCOMPILER_H_
|
||||
|
||||
+8
-17
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include "../../../stdafx.h"
|
||||
#include "../../fmt/format.h"
|
||||
|
||||
#include <squirrel.h>
|
||||
#include "sqpcheader.h"
|
||||
@@ -63,16 +64,9 @@ SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si)
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
void SQVM::Raise_Error(const SQChar *s, ...)
|
||||
void SQVM::Raise_Error(const std::string &msg)
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl, s);
|
||||
size_t len = strlen(s)+(NUMBER_MAX_CHAR*2);
|
||||
char *buffer = MallocT<char>(len + 1);
|
||||
vseprintf(buffer, buffer + len, s, vl);
|
||||
va_end(vl);
|
||||
_lasterror = SQString::Create(_ss(this),buffer,-1);
|
||||
free(buffer);
|
||||
_lasterror = SQString::Create(_ss(this),msg);
|
||||
}
|
||||
|
||||
void SQVM::Raise_Error(SQObjectPtr &desc)
|
||||
@@ -82,15 +76,12 @@ void SQVM::Raise_Error(SQObjectPtr &desc)
|
||||
|
||||
SQString *SQVM::PrintObjVal(const SQObject &o)
|
||||
{
|
||||
char buf[NUMBER_MAX_CHAR+1];
|
||||
switch(type(o)) {
|
||||
case OT_STRING: return _string(o);
|
||||
case OT_INTEGER:
|
||||
seprintf(buf, lastof(buf), OTTD_PRINTF64, _integer(o));
|
||||
return SQString::Create(_ss(this), buf);
|
||||
return SQString::Create(_ss(this), fmt::format("{}", _integer(o)));
|
||||
case OT_FLOAT:
|
||||
seprintf(buf, lastof(buf), "%.14g", _float(o));
|
||||
return SQString::Create(_ss(this), buf);
|
||||
return SQString::Create(_ss(this), fmt::format("{:.14g}", _float(o)));
|
||||
default:
|
||||
return SQString::Create(_ss(this), GetTypeName(o));
|
||||
}
|
||||
@@ -99,13 +90,13 @@ SQString *SQVM::PrintObjVal(const SQObject &o)
|
||||
void SQVM::Raise_IdxError(const SQObject &o)
|
||||
{
|
||||
SQObjectPtr oval = PrintObjVal(o);
|
||||
Raise_Error("the index '%.50s' does not exist", _stringval(oval));
|
||||
Raise_Error(fmt::format("the index '{:.50s}' does not exist", _stringval(oval)));
|
||||
}
|
||||
|
||||
void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2)
|
||||
{
|
||||
SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2);
|
||||
Raise_Error("comparison between '%.50s' and '%.50s'", _stringval(oval1), _stringval(oval2));
|
||||
Raise_Error(fmt::format("comparison between '{:.50s}' and '{:.50s}'", _stringval(oval1), _stringval(oval2)));
|
||||
}
|
||||
|
||||
|
||||
@@ -122,5 +113,5 @@ void SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger ty
|
||||
StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes);
|
||||
}
|
||||
}
|
||||
Raise_Error("parameter " OTTD_PRINTF64 " has an invalid type '%s' ; expected: '%s'", nparam, IdType2Name((SQObjectType)type), _stringval(exptypes));
|
||||
Raise_Error(fmt::format("parameter {} has an invalid type '{}' ; expected: '{}'", nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)));
|
||||
}
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ public:
|
||||
new (f) SQFunctionProto(ninstructions, nliterals, nparameters, nfunctions, noutervalues, nlineinfos, nlocalvarinfos, ndefaultparams);
|
||||
return f;
|
||||
}
|
||||
void Release(){
|
||||
void Release() override {
|
||||
_DESTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals);
|
||||
_DESTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters);
|
||||
_DESTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions);
|
||||
|
||||
+10
-11
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include "../../../stdafx.h"
|
||||
#include "../../fmt/format.h"
|
||||
|
||||
#include "sqpcheader.h"
|
||||
#include "sqcompiler.h"
|
||||
@@ -83,16 +84,16 @@ SQInstructionDesc g_InstrDesc[]={
|
||||
void DumpLiteral(SQObjectPtr &o)
|
||||
{
|
||||
switch(type(o)){
|
||||
case OT_STRING: printf("\"%s\"",_stringval(o));break;
|
||||
case OT_FLOAT: printf("{%f}",_float(o));break;
|
||||
case OT_INTEGER: printf("{" OTTD_PRINTF64 "}",_integer(o));break;
|
||||
case OT_BOOL: printf("%s",_integer(o)?"true":"false");break;
|
||||
default: printf("(%s %p)",GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler
|
||||
case OT_STRING: fmt::print("\"{}\"",_stringval(o));break;
|
||||
case OT_FLOAT: fmt::print("{{{}}}",_float(o));break;
|
||||
case OT_INTEGER: fmt::print("{{{}}}",_integer(o));break;
|
||||
case OT_BOOL: fmt::print(_integer(o)?"true":"false");break;
|
||||
default: fmt::print("({} {})",GetTypeName(o),(size_t)(void*)_rawval(o));break; break; //shut up compiler
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed)
|
||||
SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent)
|
||||
{
|
||||
_nliterals = 0;
|
||||
_literals = SQTable::Create(ss,0);
|
||||
@@ -105,15 +106,13 @@ SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc
|
||||
_traps = 0;
|
||||
_returnexp = 0;
|
||||
_varparams = false;
|
||||
_errfunc = efunc;
|
||||
_errtarget = ed;
|
||||
_bgenerator = false;
|
||||
|
||||
}
|
||||
|
||||
void SQFuncState::Error(const SQChar *err)
|
||||
{
|
||||
_errfunc(_errtarget,err);
|
||||
throw CompileException(err);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_DUMP
|
||||
@@ -549,7 +548,7 @@ SQFunctionProto *SQFuncState::BuildProto()
|
||||
SQFuncState *SQFuncState::PushChildState(SQSharedState *ss)
|
||||
{
|
||||
SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState));
|
||||
new (child) SQFuncState(ss,this,_errfunc,_errtarget);
|
||||
new (child) SQFuncState(ss,this);
|
||||
_childstates.push_back(child);
|
||||
return child;
|
||||
}
|
||||
@@ -563,7 +562,7 @@ void SQFuncState::PopChildState()
|
||||
|
||||
SQFuncState::~SQFuncState()
|
||||
{
|
||||
while(_childstates.size() > 0)
|
||||
while(!_childstates.empty())
|
||||
{
|
||||
PopChildState();
|
||||
}
|
||||
|
||||
+2
-5
@@ -6,12 +6,12 @@
|
||||
|
||||
struct SQFuncState
|
||||
{
|
||||
SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed);
|
||||
SQFuncState(SQSharedState *ss,SQFuncState *parent);
|
||||
~SQFuncState();
|
||||
#ifdef _DEBUG_DUMP
|
||||
void Dump(SQFunctionProto *func);
|
||||
#endif
|
||||
void Error(const SQChar *err);
|
||||
[[noreturn]] void Error(const SQChar *err);
|
||||
SQFuncState *PushChildState(SQSharedState *ss);
|
||||
void PopChildState();
|
||||
void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);}
|
||||
@@ -75,9 +75,6 @@ struct SQFuncState
|
||||
SQSharedState *_sharedstate;
|
||||
sqvector<SQFuncState*> _childstates;
|
||||
SQInteger GetConstant(const SQObject &cons);
|
||||
private:
|
||||
CompilerErrorFunc _errfunc;
|
||||
void *_errtarget;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+6
-9
@@ -26,7 +26,7 @@ SQLexer::~SQLexer()
|
||||
_keywords->Release();
|
||||
}
|
||||
|
||||
void SQLexer::APPEND_CHAR(WChar c)
|
||||
void SQLexer::APPEND_CHAR(char32_t c)
|
||||
{
|
||||
char buf[4];
|
||||
size_t chars = Utf8Encode(buf, c);
|
||||
@@ -35,10 +35,8 @@ void SQLexer::APPEND_CHAR(WChar c)
|
||||
}
|
||||
}
|
||||
|
||||
SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed)
|
||||
SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up)
|
||||
{
|
||||
_errfunc = efunc;
|
||||
_errtarget = ed;
|
||||
_sharedstate = ss;
|
||||
_keywords = SQTable::Create(ss, 26);
|
||||
ADD_KEYWORD(while, TK_WHILE);
|
||||
@@ -94,14 +92,14 @@ SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerE
|
||||
Next();
|
||||
}
|
||||
|
||||
NORETURN void SQLexer::Error(const SQChar *err)
|
||||
[[noreturn]] void SQLexer::Error(const SQChar *err)
|
||||
{
|
||||
_errfunc(_errtarget,err);
|
||||
throw CompileException(err);
|
||||
}
|
||||
|
||||
void SQLexer::Next()
|
||||
{
|
||||
WChar t = _readf(_up);
|
||||
char32_t t = _readf(_up);
|
||||
if(t > MAX_CHAR) Error("Invalid character");
|
||||
if(t != 0) {
|
||||
_currdata = t;
|
||||
@@ -177,7 +175,6 @@ SQInteger SQLexer::Lex()
|
||||
else if ( CUR_CHAR == '-' ) { NEXT(); RETURN_TOKEN(TK_NEWSLOT); }
|
||||
else if ( CUR_CHAR == '<' ) { NEXT(); RETURN_TOKEN(TK_SHIFTL); }
|
||||
else if ( CUR_CHAR == '/' ) { NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); }
|
||||
//else if ( CUR_CHAR == '[' ) { NEXT(); ReadMultilineString(); RETURN_TOKEN(TK_STRING_LITERAL); }
|
||||
else { RETURN_TOKEN('<') }
|
||||
case '>':
|
||||
NEXT();
|
||||
@@ -288,7 +285,7 @@ SQInteger SQLexer::GetIDType(SQChar *s)
|
||||
}
|
||||
|
||||
|
||||
SQInteger SQLexer::ReadString(WChar ndelim,bool verbatim)
|
||||
SQInteger SQLexer::ReadString(char32_t ndelim,bool verbatim)
|
||||
{
|
||||
INIT_TEMP_STRING();
|
||||
NEXT();
|
||||
|
||||
+5
-7
@@ -5,13 +5,13 @@
|
||||
struct SQLexer
|
||||
{
|
||||
~SQLexer();
|
||||
SQLexer(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed);
|
||||
NORETURN void Error(const SQChar *err);
|
||||
SQLexer(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up);
|
||||
[[noreturn]] void Error(const SQChar *err);
|
||||
SQInteger Lex();
|
||||
const SQChar *Tok2Str(SQInteger tok);
|
||||
private:
|
||||
SQInteger GetIDType(SQChar *s);
|
||||
SQInteger ReadString(WChar ndelim,bool verbatim);
|
||||
SQInteger ReadString(char32_t ndelim,bool verbatim);
|
||||
SQInteger ReadNumber();
|
||||
void LexBlockComment();
|
||||
SQInteger ReadID();
|
||||
@@ -19,7 +19,7 @@ private:
|
||||
SQInteger _curtoken;
|
||||
SQTable *_keywords;
|
||||
void INIT_TEMP_STRING() { _longstr.resize(0); }
|
||||
void APPEND_CHAR(WChar c);
|
||||
void APPEND_CHAR(char32_t c);
|
||||
void TERMINATE_BUFFER() { _longstr.push_back('\0'); }
|
||||
|
||||
public:
|
||||
@@ -32,11 +32,9 @@ public:
|
||||
SQFloat _fvalue;
|
||||
SQLEXREADFUNC _readf;
|
||||
SQUserPointer _up;
|
||||
WChar _currdata;
|
||||
char32_t _currdata;
|
||||
SQSharedState *_sharedstate;
|
||||
sqvector<SQChar> _longstr;
|
||||
CompilerErrorFunc _errfunc;
|
||||
void *_errtarget;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+6
-5
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include "../../../stdafx.h"
|
||||
#include "../../fmt/format.h"
|
||||
|
||||
#include "sqpcheader.h"
|
||||
#include "sqvm.h"
|
||||
@@ -283,7 +284,7 @@ bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o
|
||||
case OT_NULL:
|
||||
break;
|
||||
default:
|
||||
v->Raise_Error("cannot serialize a %s",GetTypeName(o));
|
||||
v->Raise_Error(fmt::format("cannot serialize a {}",GetTypeName(o)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -313,7 +314,7 @@ bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)
|
||||
o=_null_;
|
||||
break;
|
||||
default:
|
||||
v->Raise_Error("cannot serialize a %s",IdType2Name(t));
|
||||
v->Raise_Error(fmt::format("cannot serialize a {}",IdType2Name(t)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -446,11 +447,11 @@ bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr
|
||||
|
||||
for(i = 0; i < noutervalues; i++){
|
||||
SQUnsignedInteger type;
|
||||
SQObjectPtr name;
|
||||
SQObjectPtr value_name;
|
||||
_CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger)));
|
||||
_CHECK_IO(ReadObject(v, up, read, o));
|
||||
_CHECK_IO(ReadObject(v, up, read, name));
|
||||
f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type);
|
||||
_CHECK_IO(ReadObject(v, up, read, value_name));
|
||||
f->_outervalues[i] = SQOuterVar(value_name,o, (SQOuterType)type);
|
||||
}
|
||||
_CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
|
||||
|
||||
|
||||
+5
-5
@@ -76,7 +76,7 @@ struct SQRefCounted
|
||||
}
|
||||
|
||||
/* Never used but required. */
|
||||
inline void operator delete(void *ptr) { NOT_REACHED(); }
|
||||
inline void operator delete(void *) { NOT_REACHED(); }
|
||||
|
||||
private:
|
||||
size_t size;
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
|
||||
struct SQWeakRef : SQRefCounted
|
||||
{
|
||||
void Release();
|
||||
void Release() override;
|
||||
SQObject _obj;
|
||||
};
|
||||
|
||||
@@ -107,7 +107,7 @@ struct SQObjectPtr;
|
||||
(obj)->_uiRef--; \
|
||||
if((obj)->_uiRef == 0) \
|
||||
(obj)->Release(); \
|
||||
(obj) = NULL; \
|
||||
(obj) = nullptr; \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ struct SQCollectable : public SQRefCounted {
|
||||
SQCollectable *_next;
|
||||
SQCollectable *_prev;
|
||||
SQSharedState *_sharedstate;
|
||||
virtual void Release()=0;
|
||||
void Release() override=0;
|
||||
virtual void EnqueueMarkObjectForChildren(class SQGCMarkerQueue &queue)=0;
|
||||
void UnMark();
|
||||
virtual void Finalize()=0;
|
||||
@@ -417,7 +417,7 @@ public:
|
||||
#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj)
|
||||
#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);}
|
||||
#define CHAINABLE_OBJ SQCollectable
|
||||
#define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;}
|
||||
#define INIT_CHAIN() {_next=nullptr;_prev=nullptr;_sharedstate=ss;}
|
||||
#else
|
||||
|
||||
#define ADD_TO_CHAIN(chain,obj) ((void)0)
|
||||
|
||||
+6
-6
@@ -201,7 +201,7 @@ SQSharedState::~SQSharedState()
|
||||
t = nx;
|
||||
}
|
||||
}
|
||||
// assert(_gc_chain==NULL); //just to proove a theory
|
||||
// assert(_gc_chain==nullptr); //just to proove a theory
|
||||
while(_gc_chain){
|
||||
_gc_chain->_uiRef--;
|
||||
_gc_chain->Release();
|
||||
@@ -246,9 +246,9 @@ void SQSharedState::DelayFinalFree(SQCollectable *collectable)
|
||||
if (!this->_collectable_free_processing) {
|
||||
this->_collectable_free_processing = true;
|
||||
while (!this->_collectable_free_queue.empty()) {
|
||||
SQCollectable *collectable = this->_collectable_free_queue.back();
|
||||
SQCollectable *collectable_to_free = this->_collectable_free_queue.back();
|
||||
this->_collectable_free_queue.pop_back();
|
||||
collectable->FinalFree();
|
||||
collectable_to_free->FinalFree();
|
||||
}
|
||||
this->_collectable_free_processing = false;
|
||||
}
|
||||
@@ -274,7 +274,7 @@ void SQSharedState::EnqueueMarkObject(SQObjectPtr &o,SQGCMarkerQueue &queue)
|
||||
}
|
||||
|
||||
|
||||
SQInteger SQSharedState::CollectGarbage(SQVM *vm)
|
||||
SQInteger SQSharedState::CollectGarbage(SQVM *)
|
||||
{
|
||||
SQInteger n=0;
|
||||
SQVM *vms = _thread(_root_vm);
|
||||
@@ -453,7 +453,7 @@ void RefTable::Resize(SQUnsignedInteger size)
|
||||
[[maybe_unused]] SQUnsignedInteger nfound = 0;
|
||||
for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
|
||||
if(type(t->obj) != OT_NULL) {
|
||||
//add back;
|
||||
//add back
|
||||
assert(t->refs != 0);
|
||||
RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
|
||||
nn->refs = t->refs;
|
||||
@@ -513,7 +513,7 @@ void RefTable::AllocNodes(SQUnsignedInteger size)
|
||||
bucks[n] = nullptr;
|
||||
temp->refs = 0;
|
||||
new (&temp->obj) SQObjectPtr;
|
||||
temp->next = temp+1;
|
||||
temp->next = &temp[1];
|
||||
temp++;
|
||||
}
|
||||
bucks[n] = nullptr;
|
||||
|
||||
+2
-1
@@ -17,8 +17,9 @@ struct SQString : public SQRefCounted
|
||||
~SQString(){}
|
||||
public:
|
||||
static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 );
|
||||
static SQString *Create(SQSharedState *ss, const std::string &str) { return Create(ss, str.data(), str.size()); }
|
||||
SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);
|
||||
void Release();
|
||||
void Release() override;
|
||||
SQSharedState *_sharedstate;
|
||||
SQString *_next; //chain for the string table
|
||||
SQInteger _len;
|
||||
|
||||
+3
-3
@@ -18,10 +18,10 @@ struct SQUserData : SQDelegable
|
||||
return ud;
|
||||
}
|
||||
#ifndef NO_GARBAGE_COLLECTOR
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue);
|
||||
void Finalize(){SetDelegate(nullptr);}
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override;
|
||||
void Finalize() override {SetDelegate(nullptr);}
|
||||
#endif
|
||||
void Release() {
|
||||
void Release() override {
|
||||
if (_hook) _hook(_val,_size);
|
||||
SQInteger tsize = _size - 1;
|
||||
this->~SQUserData();
|
||||
|
||||
+52
-43
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include "../../../stdafx.h"
|
||||
#include "../../fmt/format.h"
|
||||
|
||||
#include <squirrel.h>
|
||||
#include "sqpcheader.h"
|
||||
@@ -54,7 +55,7 @@ bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,con
|
||||
default: { Raise_Error("internal vm error bitwise op failed"); return false; }
|
||||
}
|
||||
}
|
||||
else { Raise_Error("bitwise op between '%s' and '%s'",GetTypeName(o1),GetTypeName(o2)); return false;}
|
||||
else { Raise_Error(fmt::format("bitwise op between '{}' and '{}'",GetTypeName(o1),GetTypeName(o2))); return false;}
|
||||
trg = res;
|
||||
return true;
|
||||
}
|
||||
@@ -94,7 +95,7 @@ bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,
|
||||
if(!StringCat(o1, o2, trg)) return false;
|
||||
}
|
||||
else if(!ArithMetaMethod(op,o1,o2,trg)) {
|
||||
Raise_Error("arith op %c on between '%s' and '%s'",(char)op,GetTypeName(o1),GetTypeName(o2)); return false;
|
||||
Raise_Error(fmt::format("arith op {} on between '{}' and '{}'",(char)op,GetTypeName(o1),GetTypeName(o2))); return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -115,6 +116,8 @@ SQVM::SQVM(SQSharedState *ss)
|
||||
_can_suspend = false;
|
||||
_in_stackoverflow = false;
|
||||
_ops_till_suspend = 0;
|
||||
_ops_till_suspend_error_threshold = INT64_MIN;
|
||||
_ops_till_suspend_error_label = nullptr;
|
||||
_callsstack = nullptr;
|
||||
_callsstacksize = 0;
|
||||
_alloccallsstacksize = 0;
|
||||
@@ -140,7 +143,6 @@ void SQVM::Finalize()
|
||||
SQVM::~SQVM()
|
||||
{
|
||||
Finalize();
|
||||
//sq_free(_callsstack,_alloccallsstacksize*sizeof(CallInfo));
|
||||
REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
|
||||
}
|
||||
|
||||
@@ -184,7 +186,7 @@ bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o)
|
||||
}
|
||||
default:break; //shutup compiler
|
||||
}
|
||||
Raise_Error("attempt to negate a %s", GetTypeName(o));
|
||||
Raise_Error(fmt::format("attempt to negate a {}", GetTypeName(o)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -215,7 +217,7 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
|
||||
_RET_SUCCEED(_integer(res))
|
||||
}
|
||||
}
|
||||
FALLTHROUGH;
|
||||
[[fallthrough]];
|
||||
default:
|
||||
_RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 );
|
||||
}
|
||||
@@ -262,19 +264,19 @@ bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObject
|
||||
|
||||
void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
|
||||
{
|
||||
char buf[64];
|
||||
std::string str;
|
||||
switch(type(o)) {
|
||||
case OT_STRING:
|
||||
res = o;
|
||||
return;
|
||||
case OT_FLOAT:
|
||||
seprintf(buf, lastof(buf),"%g",_float(o));
|
||||
str = fmt::format("{}",_float(o));
|
||||
break;
|
||||
case OT_INTEGER:
|
||||
seprintf(buf, lastof(buf),OTTD_PRINTF64,_integer(o));
|
||||
str = fmt::format("{}",_integer(o));
|
||||
break;
|
||||
case OT_BOOL:
|
||||
seprintf(buf, lastof(buf),_integer(o)?"true":"false");
|
||||
str = _integer(o)?"true":"false";
|
||||
break;
|
||||
case OT_TABLE:
|
||||
case OT_USERDATA:
|
||||
@@ -287,11 +289,11 @@ void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
|
||||
//else keeps going to the default
|
||||
}
|
||||
}
|
||||
FALLTHROUGH;
|
||||
[[fallthrough]];
|
||||
default:
|
||||
seprintf(buf, lastof(buf),"(%s : 0x%p)",GetTypeName(o),(void*)_rawval(o));
|
||||
str = fmt::format("({} : 0x{:08X})",GetTypeName(o),(size_t)(void*)_rawval(o));
|
||||
}
|
||||
res = SQString::Create(_ss(this),buf);
|
||||
res = SQString::Create(_ss(this),str);
|
||||
}
|
||||
|
||||
|
||||
@@ -539,16 +541,16 @@ bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr
|
||||
_generator(o1)->Resume(this, arg_2+1);
|
||||
_FINISH(0);
|
||||
}
|
||||
FALLTHROUGH;
|
||||
[[fallthrough]];
|
||||
default:
|
||||
Raise_Error("cannot iterate %s", GetTypeName(o1));
|
||||
Raise_Error(fmt::format("cannot iterate {}", GetTypeName(o1)));
|
||||
}
|
||||
return false; //cannot be hit(just to avoid warnings)
|
||||
}
|
||||
|
||||
bool SQVM::DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2)
|
||||
{
|
||||
if(type(o1) != OT_TABLE) { Raise_Error("delegating a '%s'", GetTypeName(o1)); return false; }
|
||||
if(type(o1) != OT_TABLE) { Raise_Error(fmt::format("delegating a '{}'", GetTypeName(o1))); return false; }
|
||||
switch(type(o2)) {
|
||||
case OT_TABLE:
|
||||
if(!_table(o1)->SetDelegate(_table(o2))){
|
||||
@@ -560,7 +562,7 @@ bool SQVM::DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2)
|
||||
_table(o1)->SetDelegate(nullptr);
|
||||
break;
|
||||
default:
|
||||
Raise_Error("using '%s' as delegate", GetTypeName(o2));
|
||||
Raise_Error(fmt::format("using '{}' as delegate", GetTypeName(o2)));
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@@ -616,7 +618,7 @@ bool SQVM::GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &index,CallInfo *ci)
|
||||
return false;
|
||||
}
|
||||
if(!sq_isnumeric(index)){
|
||||
Raise_Error("indexing 'vargv' with %s",GetTypeName(index));
|
||||
Raise_Error(fmt::format("indexing 'vargv' with {}",GetTypeName(index)));
|
||||
return false;
|
||||
}
|
||||
SQInteger idx = tointeger(index);
|
||||
@@ -630,7 +632,7 @@ bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes
|
||||
SQClass *base = nullptr;
|
||||
SQObjectPtr attrs;
|
||||
if(baseclass != -1) {
|
||||
if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error("trying to inherit from a %s",GetTypeName(_stack._vals[_stackbase+baseclass])); return false; }
|
||||
if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(fmt::format("trying to inherit from a {}",GetTypeName(_stack._vals[_stackbase+baseclass]))); return false; }
|
||||
base = _class(_stack._vals[_stackbase + baseclass]);
|
||||
}
|
||||
if(attributes != MAX_FUNC_STACKSIZE) {
|
||||
@@ -685,7 +687,7 @@ bool SQVM::GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target)
|
||||
case OT_CLASS: target = _class(o)->_base?_class(o)->_base:_null_;
|
||||
break;
|
||||
default:
|
||||
Raise_Error("the %s type doesn't have a parent slot", GetTypeName(o));
|
||||
Raise_Error(fmt::format("the {} type doesn't have a parent slot", GetTypeName(o)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -712,7 +714,6 @@ bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQIn
|
||||
return false;
|
||||
}
|
||||
if (_funcproto(_closure(temp_reg)->_function)->_bgenerator) {
|
||||
//SQFunctionProto *f = _funcproto(_closure(temp_reg)->_function);
|
||||
SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(temp_reg));
|
||||
_GUARD(gen->Yield(this));
|
||||
Return(1, ci->_target, temp_reg);
|
||||
@@ -745,10 +746,16 @@ exception_restore:
|
||||
{
|
||||
DecreaseOps(1);
|
||||
if (ShouldSuspend()) { _suspended = SQTrue; _suspended_traps = traps; return true; }
|
||||
if (IsOpsTillSuspendError()) {
|
||||
Raise_Error(fmt::format("excessive CPU usage in {}", _ops_till_suspend_error_label));
|
||||
SQ_THROW();
|
||||
}
|
||||
|
||||
const SQInstruction &_i_ = *ci->_ip++;
|
||||
//dumpstack(_stackbase);
|
||||
//printf("%s %d %d %d %d\n",g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);
|
||||
#ifdef _DEBUG_DUMP
|
||||
dumpstack(_stackbase);
|
||||
printf("%s %d %d %d %d\n",g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);
|
||||
#endif
|
||||
switch(_i_.op)
|
||||
{
|
||||
case _OP_LINE:
|
||||
@@ -769,7 +776,7 @@ exception_restore:
|
||||
ct_stackbase = _stackbase;
|
||||
goto common_call;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
[[fallthrough]];
|
||||
case _OP_CALL: {
|
||||
ct_tailcall = false;
|
||||
ct_target = arg0;
|
||||
@@ -839,11 +846,11 @@ common_call:
|
||||
STK(ct_target) = clo;
|
||||
break;
|
||||
}
|
||||
Raise_Error("attempt to call '%s'", GetTypeName(clo));
|
||||
Raise_Error(fmt::format("attempt to call '{}'", GetTypeName(clo)));
|
||||
SQ_THROW();
|
||||
}
|
||||
default:
|
||||
Raise_Error("attempt to call '%s'", GetTypeName(clo));
|
||||
Raise_Error(fmt::format("attempt to call '{}'", GetTypeName(clo)));
|
||||
SQ_THROW();
|
||||
}
|
||||
}
|
||||
@@ -945,7 +952,7 @@ common_call:
|
||||
case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,false)?_true_:_false_;continue;
|
||||
case _OP_INSTANCEOF:
|
||||
if(type(STK(arg1)) != OT_CLASS || type(STK(arg2)) != OT_INSTANCE)
|
||||
{Raise_Error("cannot apply instanceof between a %s and a %s",GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();}
|
||||
{Raise_Error(fmt::format("cannot apply instanceof between a {} and a {}",GetTypeName(STK(arg1)),GetTypeName(STK(arg2)))); SQ_THROW();}
|
||||
TARGET = _instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?_true_:_false_;
|
||||
continue;
|
||||
case _OP_AND:
|
||||
@@ -968,7 +975,7 @@ common_call:
|
||||
TARGET = SQInteger(~t);
|
||||
continue;
|
||||
}
|
||||
Raise_Error("attempt to perform a bitwise op on a %s", GetTypeName(STK(arg1)));
|
||||
Raise_Error(fmt::format("attempt to perform a bitwise op on a {}", GetTypeName(STK(arg1))));
|
||||
SQ_THROW();
|
||||
case _OP_CLOSURE: {
|
||||
SQClosure *c = ci->_closure._unVal.pClosure;
|
||||
@@ -983,7 +990,7 @@ common_call:
|
||||
traps -= ci->_etraps;
|
||||
if(sarg1 != MAX_FUNC_STACKSIZE) STK(arg1) = temp_reg;
|
||||
}
|
||||
else { Raise_Error("trying to yield a '%s',only genenerator can be yielded", GetTypeName(ci->_closure)); SQ_THROW();}
|
||||
else { Raise_Error(fmt::format("trying to yield a '{}',only genenerator can be yielded", GetTypeName(ci->_closure))); SQ_THROW();}
|
||||
if(Return(arg0, arg1, temp_reg)){
|
||||
assert(traps == 0);
|
||||
outres = temp_reg;
|
||||
@@ -993,7 +1000,7 @@ common_call:
|
||||
}
|
||||
continue;
|
||||
case _OP_RESUME:
|
||||
if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error("trying to resume a '%s',only genenerator can be resumed", GetTypeName(STK(arg1))); SQ_THROW();}
|
||||
if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(fmt::format("trying to resume a '{}',only genenerator can be resumed", GetTypeName(STK(arg1)))); SQ_THROW();}
|
||||
_GUARD(_generator(STK(arg1))->Resume(this, arg0));
|
||||
traps += ci->_etraps;
|
||||
continue;
|
||||
@@ -1009,7 +1016,7 @@ common_call:
|
||||
case _OP_DELEGATE: _GUARD(DELEGATE_OP(TARGET,STK(arg1),STK(arg2))); continue;
|
||||
case _OP_CLONE:
|
||||
if(!Clone(STK(arg1), TARGET))
|
||||
{ Raise_Error("cloning a %s", GetTypeName(STK(arg1))); SQ_THROW();}
|
||||
{ Raise_Error(fmt::format("cloning a {}", GetTypeName(STK(arg1)))); SQ_THROW();}
|
||||
continue;
|
||||
case _OP_TYPEOF: TypeOf(STK(arg1), TARGET); continue;
|
||||
case _OP_PUSHTRAP:{
|
||||
@@ -1053,7 +1060,9 @@ common_call:
|
||||
exception_trap:
|
||||
{
|
||||
SQObjectPtr currerror = _lasterror;
|
||||
// dumpstack(_stackbase);
|
||||
#ifdef _DEBUG_DUMP
|
||||
dumpstack(_stackbase);
|
||||
#endif
|
||||
SQInteger n = 0;
|
||||
SQInteger last_top = _top;
|
||||
if(ci) {
|
||||
@@ -1062,11 +1071,11 @@ exception_trap:
|
||||
if(traps) {
|
||||
do {
|
||||
if(ci->_etraps > 0) {
|
||||
SQExceptionTrap &et = _etraps.top();
|
||||
ci->_ip = et._ip;
|
||||
_top = et._stacksize;
|
||||
_stackbase = et._stackbase;
|
||||
_stack._vals[_stackbase+et._extarget] = currerror;
|
||||
SQExceptionTrap &trap = _etraps.top();
|
||||
ci->_ip = trap._ip;
|
||||
_top = trap._stacksize;
|
||||
_stackbase = trap._stackbase;
|
||||
_stack._vals[_stackbase+trap._extarget] = currerror;
|
||||
_etraps.pop_back(); traps--; ci->_etraps--;
|
||||
CLEARSTACK(last_top);
|
||||
goto exception_restore;
|
||||
@@ -1329,7 +1338,7 @@ bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr
|
||||
return true;
|
||||
}
|
||||
}
|
||||
FALLTHROUGH;
|
||||
[[fallthrough]];
|
||||
case OT_USERDATA:
|
||||
if(_delegable(self)->_delegate) {
|
||||
SQObjectPtr t;
|
||||
@@ -1346,10 +1355,10 @@ bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr
|
||||
}
|
||||
break;
|
||||
case OT_ARRAY:
|
||||
if(!sq_isnumeric(key)) {Raise_Error("indexing %s with %s",GetTypeName(self),GetTypeName(key)); return false; }
|
||||
if(!sq_isnumeric(key)) {Raise_Error(fmt::format("indexing {} with {}",GetTypeName(self),GetTypeName(key))); return false; }
|
||||
return _array(self)->Set(tointeger(key),val);
|
||||
default:
|
||||
Raise_Error("trying to set '%s'",GetTypeName(self));
|
||||
Raise_Error(fmt::format("trying to set '{}'",GetTypeName(self)));
|
||||
return false;
|
||||
}
|
||||
if(fetchroot) {
|
||||
@@ -1418,13 +1427,13 @@ bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObject
|
||||
}
|
||||
else {
|
||||
SQObjectPtr oval = PrintObjVal(key);
|
||||
Raise_Error("the property '%s' already exists",_stringval(oval));
|
||||
Raise_Error(fmt::format("the property '{}' already exists",_stringval(oval)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Raise_Error("indexing %s with %s",GetTypeName(self),GetTypeName(key));
|
||||
Raise_Error(fmt::format("indexing {} with {}",GetTypeName(self),GetTypeName(key)));
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@@ -1455,7 +1464,7 @@ bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr
|
||||
}
|
||||
}
|
||||
else {
|
||||
Raise_Error("cannot delete a slot from %s",GetTypeName(self));
|
||||
Raise_Error(fmt::format("cannot delete a slot from {}",GetTypeName(self)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1463,7 +1472,7 @@ bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Raise_Error("attempt to delete a slot from a %s",GetTypeName(self));
|
||||
Raise_Error(fmt::format("attempt to delete a slot from a {}",GetTypeName(self)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
+13
-7
@@ -36,7 +36,6 @@ struct SQVM : public CHAINABLE_OBJ
|
||||
};
|
||||
|
||||
struct CallInfo{
|
||||
//CallInfo() { _generator._type = OT_NULL;}
|
||||
SQInstruction *_ip;
|
||||
SQObjectPtr *_literals;
|
||||
SQObjectPtr _closure;
|
||||
@@ -81,7 +80,7 @@ public:
|
||||
SQString *PrintObjVal(const SQObject &o);
|
||||
|
||||
|
||||
void Raise_Error(const SQChar *s, ...) WARN_FORMAT(2, 3);
|
||||
void Raise_Error(const std::string &msg);
|
||||
void Raise_Error(SQObjectPtr &desc);
|
||||
void Raise_IdxError(const SQObject &o);
|
||||
void Raise_CompareError(const SQObject &o1, const SQObject &o2);
|
||||
@@ -113,16 +112,16 @@ public:
|
||||
#endif
|
||||
|
||||
#ifndef NO_GARBAGE_COLLECTOR
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue);
|
||||
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override;
|
||||
#endif
|
||||
void Finalize();
|
||||
void Finalize() override;
|
||||
void GrowCallStack() {
|
||||
SQInteger newsize = _alloccallsstacksize*2;
|
||||
_callstackdata.resize(newsize);
|
||||
_callsstack = &_callstackdata[0];
|
||||
_alloccallsstacksize = newsize;
|
||||
}
|
||||
void Release(){ sq_delete(this,SQVM); } //does nothing
|
||||
void Release() override { sq_delete(this,SQVM); } //does nothing
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//stack functions for the api
|
||||
void Remove(SQInteger n);
|
||||
@@ -169,6 +168,8 @@ public:
|
||||
|
||||
SQBool _can_suspend;
|
||||
SQInteger _ops_till_suspend;
|
||||
SQInteger _ops_till_suspend_error_threshold;
|
||||
const char *_ops_till_suspend_error_label;
|
||||
SQBool _in_stackoverflow;
|
||||
|
||||
bool ShouldSuspend()
|
||||
@@ -176,6 +177,11 @@ public:
|
||||
return _can_suspend && _ops_till_suspend <= 0;
|
||||
}
|
||||
|
||||
bool IsOpsTillSuspendError()
|
||||
{
|
||||
return _ops_till_suspend < _ops_till_suspend_error_threshold;
|
||||
}
|
||||
|
||||
void DecreaseOps(SQInteger amount)
|
||||
{
|
||||
if (_ops_till_suspend - amount < _ops_till_suspend) _ops_till_suspend -= amount;
|
||||
@@ -195,7 +201,7 @@ inline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->
|
||||
#ifndef NO_GARBAGE_COLLECTOR
|
||||
#define _opt_ss(_vm_) (_vm_)->_sharedstate
|
||||
#else
|
||||
#define _opt_ss(_vm_) NULL
|
||||
#define _opt_ss(_vm_) nullptr
|
||||
#endif
|
||||
|
||||
#define PUSH_CALLINFO(v,nci){ \
|
||||
@@ -219,6 +225,6 @@ inline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->
|
||||
if(v->_callsstacksize) \
|
||||
v->ci = &v->_callsstack[v->_callsstacksize-1] ; \
|
||||
else \
|
||||
v->ci = NULL; \
|
||||
v->ci = nullptr; \
|
||||
}
|
||||
#endif //_SQVM_H_
|
||||
|
||||
+29
-6
@@ -23,6 +23,8 @@ add_subdirectory(saveload)
|
||||
add_subdirectory(sound)
|
||||
add_subdirectory(spriteloader)
|
||||
add_subdirectory(table)
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(timer)
|
||||
add_subdirectory(video)
|
||||
add_subdirectory(widgets)
|
||||
|
||||
@@ -31,6 +33,12 @@ add_files(
|
||||
CONDITION SSE_FOUND
|
||||
)
|
||||
|
||||
add_files(
|
||||
gfx_layout_icu.cpp
|
||||
gfx_layout_icu.h
|
||||
CONDITION ICU_i18n_FOUND AND HARFBUZZ_FOUND
|
||||
)
|
||||
|
||||
add_files(
|
||||
aircraft.h
|
||||
aircraft_cmd.cpp
|
||||
@@ -107,11 +115,8 @@ add_files(
|
||||
crashlog.h
|
||||
currency.cpp
|
||||
currency.h
|
||||
date.cpp
|
||||
date_func.h
|
||||
date_gui.cpp
|
||||
date_gui.h
|
||||
date_type.h
|
||||
debug.cpp
|
||||
debug.h
|
||||
dedicated.cpp
|
||||
@@ -149,6 +154,8 @@ add_files(
|
||||
engine_gui.h
|
||||
engine_type.h
|
||||
error.h
|
||||
error.cpp
|
||||
error_func.h
|
||||
error_gui.cpp
|
||||
fileio.cpp
|
||||
fileio_func.h
|
||||
@@ -171,6 +178,8 @@ add_files(
|
||||
gfx_func.h
|
||||
gfx_layout.cpp
|
||||
gfx_layout.h
|
||||
gfx_layout_fallback.cpp
|
||||
gfx_layout_fallback.h
|
||||
gfx_type.h
|
||||
gfxinit.cpp
|
||||
gfxinit.h
|
||||
@@ -190,9 +199,10 @@ add_files(
|
||||
group_gui.h
|
||||
group_type.h
|
||||
gui.h
|
||||
guitimer_func.h
|
||||
heightmap.cpp
|
||||
heightmap.h
|
||||
help_gui.cpp
|
||||
help_gui.h
|
||||
highscore.cpp
|
||||
highscore.h
|
||||
highscore_gui.cpp
|
||||
@@ -222,6 +232,7 @@ add_files(
|
||||
league_gui.h
|
||||
league_gui.cpp
|
||||
league_type.h
|
||||
library_loader.h
|
||||
livery.h
|
||||
main_gui.cpp
|
||||
map.cpp
|
||||
@@ -274,6 +285,8 @@ add_files(
|
||||
newgrf_properties.h
|
||||
newgrf_railtype.cpp
|
||||
newgrf_railtype.h
|
||||
newgrf_roadstop.cpp
|
||||
newgrf_roadstop.h
|
||||
newgrf_roadtype.cpp
|
||||
newgrf_roadtype.h
|
||||
newgrf_sound.cpp
|
||||
@@ -313,6 +326,8 @@ add_files(
|
||||
order_gui.cpp
|
||||
order_type.h
|
||||
osk_gui.cpp
|
||||
palette.cpp
|
||||
palette_func.h
|
||||
pbs.cpp
|
||||
pbs.h
|
||||
progress.cpp
|
||||
@@ -367,6 +382,8 @@ add_files(
|
||||
signal.cpp
|
||||
signal_func.h
|
||||
signal_type.h
|
||||
signature.cpp
|
||||
signature.h
|
||||
signs.cpp
|
||||
signs_base.h
|
||||
signs_cmd.cpp
|
||||
@@ -378,6 +395,8 @@ add_files(
|
||||
slope_type.h
|
||||
smallmap_gui.cpp
|
||||
smallmap_gui.h
|
||||
social_integration.cpp
|
||||
social_integration.h
|
||||
sortlist_type.h
|
||||
sound.cpp
|
||||
sound_func.h
|
||||
@@ -386,6 +405,7 @@ add_files(
|
||||
sprite.h
|
||||
spritecache.cpp
|
||||
spritecache.h
|
||||
spritecache_internal.h
|
||||
station.cpp
|
||||
station_base.h
|
||||
station_cmd.cpp
|
||||
@@ -404,7 +424,6 @@ add_files(
|
||||
story_cmd.h
|
||||
story_gui.cpp
|
||||
story_type.h
|
||||
strgen/strgen.h
|
||||
string.cpp
|
||||
string_base.h
|
||||
string_func.h
|
||||
@@ -413,6 +432,7 @@ add_files(
|
||||
stringfilter_type.h
|
||||
strings.cpp
|
||||
strings_func.h
|
||||
strings_internal.h
|
||||
strings_type.h
|
||||
subsidy.cpp
|
||||
subsidy_base.h
|
||||
@@ -420,6 +440,8 @@ add_files(
|
||||
subsidy_func.h
|
||||
subsidy_gui.cpp
|
||||
subsidy_type.h
|
||||
survey.cpp
|
||||
survey.h
|
||||
tar_type.h
|
||||
terraform_cmd.cpp
|
||||
terraform_cmd.h
|
||||
@@ -492,6 +514,8 @@ add_files(
|
||||
vehicle_type.h
|
||||
vehiclelist.cpp
|
||||
vehiclelist.h
|
||||
vehiclelist_cmd.h
|
||||
vehiclelist_func.h
|
||||
viewport.cpp
|
||||
viewport_cmd.h
|
||||
viewport_func.h
|
||||
@@ -501,7 +525,6 @@ add_files(
|
||||
viewport_type.h
|
||||
void_cmd.cpp
|
||||
void_map.h
|
||||
walltime_func.h
|
||||
water.h
|
||||
water_cmd.cpp
|
||||
water_cmd.h
|
||||
|
||||
+4
-26
@@ -11,30 +11,13 @@
|
||||
#define AI_HPP
|
||||
|
||||
#include "../script/api/script_event_types.hpp"
|
||||
#include "../core/string_compare_type.hpp"
|
||||
#include "ai_scanner.hpp"
|
||||
#include <map>
|
||||
|
||||
/** A list that maps AI names to their AIInfo object. */
|
||||
typedef std::map<const char *, class ScriptInfo *, StringCompare> ScriptInfoList;
|
||||
|
||||
/**
|
||||
* Main AI class. Contains all functions needed to start, stop, save and load AIs.
|
||||
*/
|
||||
class AI {
|
||||
public:
|
||||
/**
|
||||
* The default months AIs start after each other.
|
||||
*/
|
||||
enum StartNext {
|
||||
START_NEXT_EASY = DAYS_IN_YEAR * 2,
|
||||
START_NEXT_MEDIUM = DAYS_IN_YEAR,
|
||||
START_NEXT_HARD = DAYS_IN_YEAR / 2,
|
||||
START_NEXT_MIN = 0,
|
||||
START_NEXT_MAX = 3600,
|
||||
START_NEXT_DEVIATION = 60,
|
||||
};
|
||||
|
||||
/**
|
||||
* Is it possible to start a new AI company?
|
||||
* @return True if a new AI company can be started.
|
||||
@@ -128,23 +111,18 @@ public:
|
||||
*/
|
||||
static void Save(CompanyID company);
|
||||
|
||||
/**
|
||||
* Get the number of days before the next AI should start.
|
||||
*/
|
||||
static int GetStartNextTime();
|
||||
|
||||
/** Wrapper function for AIScanner::GetAIConsoleList */
|
||||
static std::string GetConsoleList(bool newest_only = false);
|
||||
static void GetConsoleList(std::back_insert_iterator<std::string> &output_iterator, bool newest_only);
|
||||
/** Wrapper function for AIScanner::GetAIConsoleLibraryList */
|
||||
static std::string GetConsoleLibraryList();
|
||||
static void GetConsoleLibraryList(std::back_insert_iterator<std::string> &output_iterator);
|
||||
/** Wrapper function for AIScanner::GetAIInfoList */
|
||||
static const ScriptInfoList *GetInfoList();
|
||||
/** Wrapper function for AIScanner::GetUniqueAIInfoList */
|
||||
static const ScriptInfoList *GetUniqueInfoList();
|
||||
/** Wrapper function for AIScanner::FindInfo */
|
||||
static class AIInfo *FindInfo(const char *name, int version, bool force_exact_match);
|
||||
static class AIInfo *FindInfo(const std::string &name, int version, bool force_exact_match);
|
||||
/** Wrapper function for AIScanner::FindLibrary */
|
||||
static class AILibrary *FindLibrary(const char *library, int version);
|
||||
static class AILibrary *FindLibrary(const std::string &library, int version);
|
||||
|
||||
/**
|
||||
* Rescans all searchpaths for available AIs. If a used AI is no longer
|
||||
|
||||
+3
-94
@@ -16,34 +16,10 @@
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/** Configuration for AI start date, every AI has this setting. */
|
||||
ScriptConfigItem _start_date_config = {
|
||||
"start_date",
|
||||
"", // STR_AI_SETTINGS_START_DELAY
|
||||
AI::START_NEXT_MIN,
|
||||
AI::START_NEXT_MAX,
|
||||
AI::START_NEXT_MEDIUM,
|
||||
AI::START_NEXT_EASY,
|
||||
AI::START_NEXT_MEDIUM,
|
||||
AI::START_NEXT_HARD,
|
||||
AI::START_NEXT_DEVIATION,
|
||||
30,
|
||||
SCRIPTCONFIG_NONE,
|
||||
nullptr,
|
||||
false
|
||||
};
|
||||
|
||||
AIConfig::AIConfig(const AIConfig *config) : ScriptConfig(config)
|
||||
{
|
||||
/* Override start_date as per AIConfig::AddRandomDeviation().
|
||||
* This is necessary because the ScriptConfig constructor will instead call
|
||||
* ScriptConfig::AddRandomDeviation(). */
|
||||
int start_date = config->GetSetting("start_date");
|
||||
this->SetSetting("start_date", start_date != 0 ? std::max(1, this->GetSetting("start_date")) : 0);
|
||||
}
|
||||
|
||||
/* static */ AIConfig *AIConfig::GetConfig(CompanyID company, ScriptSettingSource source)
|
||||
{
|
||||
assert(company < MAX_COMPANIES);
|
||||
|
||||
AIConfig **config;
|
||||
if (source == SSS_FORCE_NEWGAME || (source == SSS_DEFAULT && _game_mode == GM_MENU)) {
|
||||
config = &_settings_newgame.ai_config[company];
|
||||
@@ -59,7 +35,7 @@ class AIInfo *AIConfig::GetInfo() const
|
||||
return static_cast<class AIInfo *>(ScriptConfig::GetInfo());
|
||||
}
|
||||
|
||||
ScriptInfo *AIConfig::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
ScriptInfo *AIConfig::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
return static_cast<ScriptInfo *>(AI::FindInfo(name, version, force_exact_match));
|
||||
}
|
||||
@@ -69,70 +45,3 @@ bool AIConfig::ResetInfo(bool force_exact_match)
|
||||
this->info = (ScriptInfo *)AI::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match);
|
||||
return this->info != nullptr;
|
||||
}
|
||||
|
||||
void AIConfig::PushExtraConfigList()
|
||||
{
|
||||
this->config_list->push_back(_start_date_config);
|
||||
}
|
||||
|
||||
void AIConfig::ClearConfigList()
|
||||
{
|
||||
/* The special casing for start_date is here to ensure that the
|
||||
* start_date setting won't change even if you chose another Script. */
|
||||
int start_date = this->GetSetting("start_date");
|
||||
|
||||
ScriptConfig::ClearConfigList();
|
||||
|
||||
this->SetSetting("start_date", start_date);
|
||||
}
|
||||
|
||||
int AIConfig::GetSetting(const char *name) const
|
||||
{
|
||||
if (this->info == nullptr) {
|
||||
SettingValueList::const_iterator it = this->settings.find(name);
|
||||
if (it == this->settings.end()) {
|
||||
assert(strcmp("start_date", name) == 0);
|
||||
switch (GetGameSettings().script.settings_profile) {
|
||||
case SP_EASY: return AI::START_NEXT_EASY;
|
||||
case SP_MEDIUM: return AI::START_NEXT_MEDIUM;
|
||||
case SP_HARD: return AI::START_NEXT_HARD;
|
||||
case SP_CUSTOM: return AI::START_NEXT_MEDIUM;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
return ScriptConfig::GetSetting(name);
|
||||
}
|
||||
|
||||
void AIConfig::SetSetting(const char *name, int value)
|
||||
{
|
||||
if (this->info == nullptr) {
|
||||
if (strcmp("start_date", name) != 0) return;
|
||||
value = Clamp(value, AI::START_NEXT_MIN, AI::START_NEXT_MAX);
|
||||
|
||||
SettingValueList::iterator it = this->settings.find(name);
|
||||
if (it != this->settings.end()) {
|
||||
(*it).second = value;
|
||||
} else {
|
||||
this->settings[stredup(name)] = value;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptConfig::SetSetting(name, value);
|
||||
}
|
||||
|
||||
void AIConfig::AddRandomDeviation()
|
||||
{
|
||||
int start_date = this->GetSetting("start_date");
|
||||
|
||||
ScriptConfig::AddRandomDeviation();
|
||||
|
||||
/* start_date = 0 is a special case, where random deviation does not occur.
|
||||
* If start_date was not already 0, then a minimum value of 1 must apply. */
|
||||
this->SetSetting("start_date", start_date != 0 ? std::max(1, this->GetSetting("start_date")) : 0);
|
||||
}
|
||||
|
||||
@@ -24,14 +24,12 @@ public:
|
||||
ScriptConfig()
|
||||
{}
|
||||
|
||||
AIConfig(const AIConfig *config);
|
||||
AIConfig(const AIConfig *config) :
|
||||
ScriptConfig(config)
|
||||
{}
|
||||
|
||||
class AIInfo *GetInfo() const;
|
||||
|
||||
int GetSetting(const char *name) const override;
|
||||
void SetSetting(const char *name, int value) override;
|
||||
void AddRandomDeviation() override;
|
||||
|
||||
/**
|
||||
* When ever the AI Scanner is reloaded, all infos become invalid. This
|
||||
* function tells AIConfig about this.
|
||||
@@ -43,9 +41,7 @@ public:
|
||||
bool ResetInfo(bool force_exact_match);
|
||||
|
||||
protected:
|
||||
void PushExtraConfigList() override;
|
||||
void ClearConfigList() override;
|
||||
ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override;
|
||||
ScriptInfo *FindInfo(const std::string &name, int version, bool force_exact_match) override;
|
||||
};
|
||||
|
||||
#endif /* AI_CONFIG_HPP */
|
||||
|
||||
+20
-32
@@ -48,6 +48,7 @@
|
||||
/* Load default data and store the name in the settings */
|
||||
config->Change(info->GetName(), -1, false, true);
|
||||
}
|
||||
if (rerandomise_ai) config->AddRandomDeviation();
|
||||
config->AnchorUnchangeableSettings();
|
||||
|
||||
Backup<CompanyID> cur_company(_current_company, company, FILE_LINE);
|
||||
@@ -62,7 +63,7 @@
|
||||
|
||||
cur_company.Restore();
|
||||
|
||||
InvalidateWindowData(WC_AI_DEBUG, 0, -1);
|
||||
InvalidateWindowClassesData(WC_SCRIPT_DEBUG, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,18 +83,16 @@
|
||||
PerformanceMeasurer framerate((PerformanceElement)(PFE_AI0 + c->index));
|
||||
cur_company.Change(c->index);
|
||||
c->ai_instance->GameLoop();
|
||||
/* Occasionally collect garbage; every 255 ticks do one company.
|
||||
* Effectively collecting garbage once every two months per AI. */
|
||||
if ((AI::frame_counter & 255) == 0 && (CompanyID)GB(AI::frame_counter, 8, 4) == c->index) {
|
||||
c->ai_instance->CollectGarbage();
|
||||
}
|
||||
} else {
|
||||
PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + c->index));
|
||||
}
|
||||
}
|
||||
cur_company.Restore();
|
||||
|
||||
/* Occasionally collect garbage; every 255 ticks do one company.
|
||||
* Effectively collecting garbage once every two months per AI. */
|
||||
if ((AI::frame_counter & 255) == 0) {
|
||||
CompanyID cid = (CompanyID)GB(AI::frame_counter, 8, 4);
|
||||
if (Company::IsValidAiID(cid)) Company::Get(cid)->ai_instance->CollectGarbage();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ uint AI::GetTick()
|
||||
@@ -115,8 +114,8 @@
|
||||
|
||||
cur_company.Restore();
|
||||
|
||||
InvalidateWindowData(WC_AI_DEBUG, 0, -1);
|
||||
CloseWindowById(WC_AI_SETTINGS, company);
|
||||
InvalidateWindowClassesData(WC_SCRIPT_DEBUG, -1);
|
||||
CloseWindowById(WC_SCRIPT_SETTINGS, company);
|
||||
}
|
||||
|
||||
/* static */ void AI::Pause(CompanyID company)
|
||||
@@ -210,7 +209,7 @@
|
||||
if (_settings_game.ai_config[c] != nullptr && _settings_game.ai_config[c]->HasScript()) {
|
||||
if (!_settings_game.ai_config[c]->ResetInfo(true)) {
|
||||
Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName());
|
||||
_settings_game.ai_config[c]->Change(nullptr);
|
||||
_settings_game.ai_config[c]->Change(std::nullopt);
|
||||
if (Company::IsValidAiID(c)) {
|
||||
/* The code belonging to an already running AI was deleted. We can only do
|
||||
* one thing here to keep everything sane and that is kill the AI. After
|
||||
@@ -227,7 +226,7 @@
|
||||
if (_settings_newgame.ai_config[c] != nullptr && _settings_newgame.ai_config[c]->HasScript()) {
|
||||
if (!_settings_newgame.ai_config[c]->ResetInfo(false)) {
|
||||
Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName());
|
||||
_settings_newgame.ai_config[c]->Change(nullptr);
|
||||
_settings_newgame.ai_config[c]->Change(std::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,25 +290,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ int AI::GetStartNextTime()
|
||||
/* static */ void AI::GetConsoleList(std::back_insert_iterator<std::string> &output_iterator, bool newest_only)
|
||||
{
|
||||
/* Find the first company which doesn't exist yet */
|
||||
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
|
||||
if (!Company::IsValidID(c)) return AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->GetSetting("start_date");
|
||||
}
|
||||
|
||||
/* Currently no AI can be started, check again in a year. */
|
||||
return DAYS_IN_YEAR;
|
||||
AI::scanner_info->GetConsoleList(output_iterator, newest_only);
|
||||
}
|
||||
|
||||
/* static */ std::string AI::GetConsoleList(bool newest_only)
|
||||
/* static */ void AI::GetConsoleLibraryList(std::back_insert_iterator<std::string> &output_iterator)
|
||||
{
|
||||
return AI::scanner_info->GetConsoleList(newest_only);
|
||||
}
|
||||
|
||||
/* static */ std::string AI::GetConsoleLibraryList()
|
||||
{
|
||||
return AI::scanner_library->GetConsoleList(true);
|
||||
AI::scanner_library->GetConsoleList(output_iterator, true);
|
||||
}
|
||||
|
||||
/* static */ const ScriptInfoList *AI::GetInfoList()
|
||||
@@ -322,12 +310,12 @@
|
||||
return AI::scanner_info->GetUniqueInfoList();
|
||||
}
|
||||
|
||||
/* static */ AIInfo *AI::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
/* static */ AIInfo *AI::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
return AI::scanner_info->FindInfo(name, version, force_exact_match);
|
||||
}
|
||||
|
||||
/* static */ AILibrary *AI::FindLibrary(const char *library, int version)
|
||||
/* static */ AILibrary *AI::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
return AI::scanner_library->FindLibrary(library, version);
|
||||
}
|
||||
@@ -340,9 +328,9 @@
|
||||
AI::scanner_library->RescanDir();
|
||||
ResetConfig();
|
||||
|
||||
InvalidateWindowData(WC_AI_LIST, 0, 1);
|
||||
SetWindowClassesDirty(WC_AI_DEBUG);
|
||||
InvalidateWindowClassesData(WC_AI_SETTINGS);
|
||||
InvalidateWindowData(WC_SCRIPT_LIST, 0, 1);
|
||||
SetWindowClassesDirty(WC_SCRIPT_DEBUG);
|
||||
InvalidateWindowClassesData(WC_SCRIPT_SETTINGS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+127
-1310
File diff suppressed because it is too large
Load Diff
@@ -10,13 +10,6 @@
|
||||
#ifndef AI_GUI_HPP
|
||||
#define AI_GUI_HPP
|
||||
|
||||
#include "../company_type.h"
|
||||
|
||||
void ShowAIListWindow(CompanyID slot);
|
||||
Window* ShowAIDebugWindow(CompanyID show_company = INVALID_COMPANY);
|
||||
void ShowAIConfigWindow();
|
||||
void ShowScriptTextfileWindow(TextfileType file_type, CompanyID slot);
|
||||
void ShowAIDebugWindowIfAIError();
|
||||
void InitializeAIGui();
|
||||
|
||||
#endif /* AI_GUI_HPP */
|
||||
|
||||
+16
-37
@@ -15,7 +15,6 @@
|
||||
#include "../debug.h"
|
||||
#include "../string_func.h"
|
||||
#include "../rev.h"
|
||||
#include <set>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -23,34 +22,34 @@
|
||||
* Check if the API version provided by the AI is supported.
|
||||
* @param api_version The API version as provided by the AI.
|
||||
*/
|
||||
static bool CheckAPIVersion(const char *api_version)
|
||||
static bool CheckAPIVersion(const std::string &api_version)
|
||||
{
|
||||
static const std::set<std::string> versions = { "0.7", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13" };
|
||||
static const std::set<std::string> versions = { "0.7", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14" };
|
||||
return versions.find(api_version) != versions.end();
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef GetClassName
|
||||
#endif /* _WIN32 */
|
||||
template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
|
||||
template <> const char *GetClassName<AIInfo, ScriptType::AI>() { return "AIInfo"; }
|
||||
|
||||
/* static */ void AIInfo::RegisterAPI(Squirrel *engine)
|
||||
{
|
||||
/* Create the AIInfo class, and add the RegisterAI function */
|
||||
DefSQClass<AIInfo, ST_AI> SQAIInfo("AIInfo");
|
||||
DefSQClass<AIInfo, ScriptType::AI> SQAIInfo("AIInfo");
|
||||
SQAIInfo.PreRegister(engine);
|
||||
SQAIInfo.AddConstructor<void (AIInfo::*)(), 1>(engine, "x");
|
||||
SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddSetting, "AddSetting");
|
||||
SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddLabels, "AddLabels");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_NONE");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "CONFIG_RANDOM");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_RANDOM"); // Deprecated, mapped to NONE.
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "CONFIG_BOOLEAN");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "CONFIG_INGAME");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_DEVELOPER, "CONFIG_DEVELOPER");
|
||||
|
||||
/* Pre 1.2 had an AI prefix */
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "AICONFIG_NONE");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "AICONFIG_RANDOM");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "AICONFIG_RANDOM"); // Deprecated, mapped to NONE.
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "AICONFIG_BOOLEAN");
|
||||
SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "AICONFIG_INGAME");
|
||||
|
||||
@@ -69,31 +68,26 @@ template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
|
||||
SQInteger res = ScriptInfo::Constructor(vm, info);
|
||||
if (res != 0) return res;
|
||||
|
||||
ScriptConfigItem config = _start_date_config;
|
||||
config.name = stredup(config.name);
|
||||
config.description = stredup(config.description);
|
||||
info->config_list.push_front(config);
|
||||
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) {
|
||||
if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "MinVersionToLoad")) {
|
||||
if (!info->engine->CallIntegerMethod(info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
} else {
|
||||
info->min_loadable_version = info->GetVersion();
|
||||
}
|
||||
/* When there is an UseAsRandomAI function, call it. */
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "UseAsRandomAI")) {
|
||||
if (!info->engine->CallBoolMethod(*info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "UseAsRandomAI")) {
|
||||
if (!info->engine->CallBoolMethod(info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR;
|
||||
} else {
|
||||
info->use_as_random = true;
|
||||
}
|
||||
/* Try to get the API version the AI is written for. */
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "GetAPIVersion")) {
|
||||
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "GetAPIVersion")) {
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!CheckAPIVersion(info->api_version)) {
|
||||
Debug(script, 1, "Loading info.nut from ({}.{}): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion());
|
||||
return SQ_ERROR;
|
||||
}
|
||||
} else {
|
||||
info->api_version = stredup("0.7");
|
||||
info->api_version = "0.7";
|
||||
}
|
||||
|
||||
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
|
||||
@@ -109,15 +103,11 @@ template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
|
||||
SQUserPointer instance;
|
||||
sq_getinstanceup(vm, 2, &instance, nullptr);
|
||||
AIInfo *info = (AIInfo *)instance;
|
||||
info->api_version = nullptr;
|
||||
info->api_version = fmt::format("{}.{}", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4));
|
||||
|
||||
SQInteger res = ScriptInfo::Constructor(vm, info);
|
||||
if (res != 0) return res;
|
||||
|
||||
char buf[8];
|
||||
seprintf(buf, lastof(buf), "%d.%d", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4));
|
||||
info->api_version = stredup(buf);
|
||||
|
||||
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
|
||||
sq_setinstanceup(vm, 2, nullptr);
|
||||
/* Register the AI to the base system */
|
||||
@@ -127,16 +117,10 @@ template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
|
||||
|
||||
AIInfo::AIInfo() :
|
||||
min_loadable_version(0),
|
||||
use_as_random(false),
|
||||
api_version(nullptr)
|
||||
use_as_random(false)
|
||||
{
|
||||
}
|
||||
|
||||
AIInfo::~AIInfo()
|
||||
{
|
||||
free(this->api_version);
|
||||
}
|
||||
|
||||
bool AIInfo::CanLoadFromVersion(int version) const
|
||||
{
|
||||
if (version == -1) return true;
|
||||
@@ -144,11 +128,6 @@ bool AIInfo::CanLoadFromVersion(int version) const
|
||||
}
|
||||
|
||||
|
||||
AILibrary::~AILibrary()
|
||||
{
|
||||
free(this->category);
|
||||
}
|
||||
|
||||
/* static */ void AILibrary::RegisterAPI(Squirrel *engine)
|
||||
{
|
||||
/* Create the AILibrary class, and add the RegisterLibrary function */
|
||||
@@ -169,7 +148,7 @@ AILibrary::~AILibrary()
|
||||
}
|
||||
|
||||
/* Cache the category */
|
||||
if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
|
||||
if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
|
||||
delete library;
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
+5
-7
@@ -16,7 +16,6 @@
|
||||
class AIInfo : public ScriptInfo {
|
||||
public:
|
||||
AIInfo();
|
||||
~AIInfo();
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
@@ -46,19 +45,18 @@ public:
|
||||
/**
|
||||
* Get the API version this AI is written for.
|
||||
*/
|
||||
const char *GetAPIVersion() const { return this->api_version; }
|
||||
const std::string &GetAPIVersion() const { return this->api_version; }
|
||||
|
||||
private:
|
||||
int min_loadable_version; ///< The AI can load savegame data if the version is equal or greater than this.
|
||||
bool use_as_random; ///< Should this AI be used when the user wants a "random AI"?
|
||||
const char *api_version; ///< API version used by this AI.
|
||||
std::string api_version; ///< API version used by this AI.
|
||||
};
|
||||
|
||||
/** All static information from an AI library like name, version, etc. */
|
||||
class AILibrary : public ScriptInfo {
|
||||
public:
|
||||
AILibrary() : ScriptInfo(), category(nullptr) {};
|
||||
~AILibrary();
|
||||
AILibrary() : ScriptInfo() {};
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
@@ -73,10 +71,10 @@ public:
|
||||
/**
|
||||
* Get the category this library is in.
|
||||
*/
|
||||
const char *GetCategory() const { return this->category; }
|
||||
const std::string &GetCategory() const { return this->category; }
|
||||
|
||||
private:
|
||||
const char *category; ///< The category this library is in.
|
||||
std::string category; ///< The category this library is in.
|
||||
};
|
||||
|
||||
#endif /* AI_INFO_HPP */
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
#include "../script/squirrel_class.hpp"
|
||||
|
||||
#include "ai_config.hpp"
|
||||
#include "ai_gui.hpp"
|
||||
#include "ai.hpp"
|
||||
|
||||
#include "../script/script_storage.hpp"
|
||||
#include "../script/script_cmd.h"
|
||||
#include "../script/script_gui.h"
|
||||
#include "ai_info.hpp"
|
||||
#include "ai_instance.hpp"
|
||||
|
||||
@@ -64,13 +64,13 @@ void AIInstance::Died()
|
||||
/* Intro is not supposed to use AI, but it may have 'dummy' AI which instant dies. */
|
||||
if (_game_mode == GM_MENU) return;
|
||||
|
||||
ShowAIDebugWindow(_current_company);
|
||||
ShowScriptDebugWindow(_current_company);
|
||||
|
||||
const AIInfo *info = AIConfig::GetConfig(_current_company, AIConfig::SSS_FORCE_GAME)->GetInfo();
|
||||
if (info != nullptr) {
|
||||
ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING);
|
||||
|
||||
if (info->GetURL() != nullptr) {
|
||||
if (!info->GetURL().empty()) {
|
||||
ScriptLog::Info("Please report the error to the following URL:");
|
||||
ScriptLog::Info(info->GetURL());
|
||||
}
|
||||
@@ -80,16 +80,15 @@ void AIInstance::Died()
|
||||
void AIInstance::LoadDummyScript()
|
||||
{
|
||||
ScriptAllocatorScope alloc_scope(this->engine);
|
||||
extern void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type);
|
||||
Script_CreateDummy(this->engine->GetVM(), STR_ERROR_AI_NO_AI_FOUND, "AI");
|
||||
}
|
||||
|
||||
int AIInstance::GetSetting(const char *name)
|
||||
int AIInstance::GetSetting(const std::string &name)
|
||||
{
|
||||
return AIConfig::GetConfig(_current_company)->GetSetting(name);
|
||||
}
|
||||
|
||||
ScriptInfo *AIInstance::FindLibrary(const char *library, int version)
|
||||
ScriptInfo *AIInstance::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
return (ScriptInfo *)AI::FindLibrary(library, version);
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ public:
|
||||
*/
|
||||
void Initialize(class AIInfo *info);
|
||||
|
||||
int GetSetting(const char *name) override;
|
||||
ScriptInfo *FindLibrary(const char *library, int version) override;
|
||||
int GetSetting(const std::string &name) override;
|
||||
ScriptInfo *FindLibrary(const std::string &library, int version) override;
|
||||
|
||||
private:
|
||||
void RegisterAPI() override;
|
||||
|
||||
+20
-31
@@ -14,6 +14,7 @@
|
||||
#include "../core/random_func.hpp"
|
||||
|
||||
#include "../script/squirrel_class.hpp"
|
||||
#include "../script/api/script_object.hpp"
|
||||
#include "ai_info.hpp"
|
||||
#include "ai_scanner.hpp"
|
||||
|
||||
@@ -34,7 +35,6 @@ void AIScannerInfo::Initialize()
|
||||
|
||||
/* Create the dummy AI */
|
||||
this->main_script = "%_dummy";
|
||||
extern void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir);
|
||||
Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai");
|
||||
}
|
||||
|
||||
@@ -48,9 +48,9 @@ AIScannerInfo::~AIScannerInfo()
|
||||
delete this->info_dummy;
|
||||
}
|
||||
|
||||
void AIScannerInfo::GetScriptName(ScriptInfo *info, char *name, const char *last)
|
||||
std::string AIScannerInfo::GetScriptName(ScriptInfo *info)
|
||||
{
|
||||
seprintf(name, last, "%s", info->GetName());
|
||||
return info->GetName();
|
||||
}
|
||||
|
||||
void AIScannerInfo::RegisterAPI(class Squirrel *engine)
|
||||
@@ -77,12 +77,7 @@ AIInfo *AIScannerInfo::SelectRandomAI() const
|
||||
}
|
||||
|
||||
/* Find a random AI */
|
||||
uint pos;
|
||||
if (_networking) {
|
||||
pos = InteractiveRandomRange(num_random_ais);
|
||||
} else {
|
||||
pos = RandomRange(num_random_ais);
|
||||
}
|
||||
uint pos = ScriptObject::GetRandomizer(OWNER_NONE).Next(num_random_ais);
|
||||
|
||||
/* Find the Nth item from the array */
|
||||
ScriptInfoList::const_iterator it = this->info_single_list.begin();
|
||||
@@ -97,39 +92,35 @@ AIInfo *AIScannerInfo::SelectRandomAI() const
|
||||
#undef GetAIInfo
|
||||
}
|
||||
|
||||
AIInfo *AIScannerInfo::FindInfo(const char *nameParam, int versionParam, bool force_exact_match)
|
||||
AIInfo *AIScannerInfo::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
if (this->info_list.size() == 0) return nullptr;
|
||||
if (nameParam == nullptr) return nullptr;
|
||||
if (this->info_list.empty()) return nullptr;
|
||||
if (name.empty()) return nullptr;
|
||||
|
||||
char ai_name[1024];
|
||||
strecpy(ai_name, nameParam, lastof(ai_name));
|
||||
strtolower(ai_name);
|
||||
|
||||
if (versionParam == -1) {
|
||||
if (version == -1) {
|
||||
/* We want to load the latest version of this AI; so find it */
|
||||
if (this->info_single_list.find(ai_name) != this->info_single_list.end()) return static_cast<AIInfo *>(this->info_single_list[ai_name]);
|
||||
auto it = this->info_single_list.find(name);
|
||||
if (it != this->info_single_list.end()) return static_cast<AIInfo *>(it->second);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (force_exact_match) {
|
||||
/* Try to find a direct 'name.version' match */
|
||||
char ai_name_tmp[1024];
|
||||
seprintf(ai_name_tmp, lastof(ai_name_tmp), "%s.%d", ai_name, versionParam);
|
||||
strtolower(ai_name_tmp);
|
||||
if (this->info_list.find(ai_name_tmp) != this->info_list.end()) return static_cast<AIInfo *>(this->info_list[ai_name_tmp]);
|
||||
std::string name_with_version = fmt::format("{}.{}", name, version);
|
||||
auto it = this->info_list.find(name_with_version);
|
||||
if (it != this->info_list.end()) return static_cast<AIInfo *>(it->second);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AIInfo *info = nullptr;
|
||||
int version = -1;
|
||||
int highest_version = -1;
|
||||
|
||||
/* See if there is a compatible AI which goes by that name, with the highest
|
||||
* version which allows loading the requested version */
|
||||
for (const auto &item : this->info_list) {
|
||||
AIInfo *i = static_cast<AIInfo *>(item.second);
|
||||
if (strcasecmp(ai_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) {
|
||||
version = item.second->GetVersion();
|
||||
if (StrEqualsIgnoreCase(name, i->GetName()) && i->CanLoadFromVersion(version) && (highest_version == -1 || i->GetVersion() > highest_version)) {
|
||||
highest_version = item.second->GetVersion();
|
||||
info = i;
|
||||
}
|
||||
}
|
||||
@@ -143,10 +134,10 @@ void AIScannerLibrary::Initialize()
|
||||
ScriptScanner::Initialize("AIScanner");
|
||||
}
|
||||
|
||||
void AIScannerLibrary::GetScriptName(ScriptInfo *info, char *name, const char *last)
|
||||
std::string AIScannerLibrary::GetScriptName(ScriptInfo *info)
|
||||
{
|
||||
AILibrary *library = static_cast<AILibrary *>(info);
|
||||
seprintf(name, last, "%s.%s", library->GetCategory(), library->GetInstanceName());
|
||||
return fmt::format("{}.{}", library->GetCategory(), library->GetInstanceName());
|
||||
}
|
||||
|
||||
void AIScannerLibrary::RegisterAPI(class Squirrel *engine)
|
||||
@@ -154,12 +145,10 @@ void AIScannerLibrary::RegisterAPI(class Squirrel *engine)
|
||||
AILibrary::RegisterAPI(engine);
|
||||
}
|
||||
|
||||
AILibrary *AIScannerLibrary::FindLibrary(const char *library, int version)
|
||||
AILibrary *AIScannerLibrary::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
/* Internally we store libraries as 'library.version' */
|
||||
char library_name[1024];
|
||||
seprintf(library_name, lastof(library_name), "%s.%d", library, version);
|
||||
strtolower(library_name);
|
||||
std::string library_name = fmt::format("{}.{}", library, version);
|
||||
|
||||
/* Check if the library + version exists */
|
||||
ScriptInfoList::iterator it = this->info_list.find(library_name);
|
||||
|
||||
@@ -27,12 +27,12 @@ public:
|
||||
|
||||
/**
|
||||
* Check if we have an AI by name and version available in our list.
|
||||
* @param nameParam The name of the AI.
|
||||
* @param versionParam The version of the AI, or -1 if you want the latest.
|
||||
* @param name The name of the AI.
|
||||
* @param version The version of the AI, or -1 if you want the latest.
|
||||
* @param force_exact_match Only match name+version, never latest.
|
||||
* @return nullptr if no match found, otherwise the AI that matched.
|
||||
*/
|
||||
class AIInfo *FindInfo(const char *nameParam, int versionParam, bool force_exact_match);
|
||||
class AIInfo *FindInfo(const std::string &name, int version, bool force_exact_match);
|
||||
|
||||
/**
|
||||
* Set the Dummy AI.
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
void SetDummyAI(class AIInfo *info);
|
||||
|
||||
protected:
|
||||
void GetScriptName(ScriptInfo *info, char *name, const char *last) override;
|
||||
std::string GetScriptName(ScriptInfo *info) override;
|
||||
const char *GetFileName() const override { return PATHSEP "info.nut"; }
|
||||
Subdirectory GetDirectory() const override { return AI_DIR; }
|
||||
const char *GetScannerName() const override { return "AIs"; }
|
||||
@@ -60,10 +60,10 @@ public:
|
||||
* @param version The version the library should have.
|
||||
* @return The library if found, nullptr otherwise.
|
||||
*/
|
||||
class AILibrary *FindLibrary(const char *library, int version);
|
||||
class AILibrary *FindLibrary(const std::string &library, int version);
|
||||
|
||||
protected:
|
||||
void GetScriptName(ScriptInfo *info, char *name, const char *last) override;
|
||||
std::string GetScriptName(ScriptInfo *info) override;
|
||||
const char *GetFileName() const override { return PATHSEP "library.nut"; }
|
||||
Subdirectory GetDirectory() const override { return AI_LIBRARY_DIR; }
|
||||
const char *GetScannerName() const override { return "AI Libraries"; }
|
||||
|
||||
+23
-21
@@ -64,15 +64,15 @@ int GetAircraftFlightLevel(T *v, bool takeoff = false);
|
||||
|
||||
/** Variables that are cached to improve performance and such. */
|
||||
struct AircraftCache {
|
||||
uint32 cached_max_range_sqr; ///< Cached squared maximum range.
|
||||
uint16 cached_max_range; ///< Cached maximum range.
|
||||
uint32_t cached_max_range_sqr; ///< Cached squared maximum range.
|
||||
uint16_t cached_max_range; ///< Cached maximum range.
|
||||
};
|
||||
|
||||
/**
|
||||
* Aircraft, helicopters, rotors and their shadows belong to this class.
|
||||
*/
|
||||
struct Aircraft FINAL : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
|
||||
uint16 crashed_counter; ///< Timer for handling crash animations.
|
||||
struct Aircraft final : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
|
||||
uint16_t crashed_counter; ///< Timer for handling crash animations.
|
||||
byte pos; ///< Next desired position of the aircraft.
|
||||
byte previous_pos; ///< Previous desired position of the aircraft.
|
||||
StationID targetairport; ///< Airport to go to next.
|
||||
@@ -89,28 +89,29 @@ struct Aircraft FINAL : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
|
||||
/** We want to 'destruct' the right class. */
|
||||
virtual ~Aircraft() { this->PreDestructor(); }
|
||||
|
||||
void MarkDirty();
|
||||
void UpdateDeltaXY();
|
||||
ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_AIRCRAFT_REVENUE : EXPENSES_AIRCRAFT_RUN; }
|
||||
bool IsPrimaryVehicle() const { return this->IsNormalAircraft(); }
|
||||
void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const;
|
||||
int GetDisplaySpeed() const { return this->cur_speed; }
|
||||
int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; }
|
||||
int GetSpeedOldUnits() const { return this->vcache.cached_max_speed * 10 / 128; }
|
||||
int GetCurrentMaxSpeed() const { return this->GetSpeedOldUnits(); }
|
||||
Money GetRunningCost() const;
|
||||
void MarkDirty() override;
|
||||
void UpdateDeltaXY() override;
|
||||
ExpensesType GetExpenseType(bool income) const override { return income ? EXPENSES_AIRCRAFT_REVENUE : EXPENSES_AIRCRAFT_RUN; }
|
||||
bool IsPrimaryVehicle() const override { return this->IsNormalAircraft(); }
|
||||
void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const override;
|
||||
int GetDisplaySpeed() const override { return this->cur_speed; }
|
||||
int GetDisplayMaxSpeed() const override { return this->vcache.cached_max_speed; }
|
||||
int GetSpeedOldUnits() const { return this->vcache.cached_max_speed * 10 / 128; }
|
||||
int GetCurrentMaxSpeed() const override { return this->GetSpeedOldUnits(); }
|
||||
Money GetRunningCost() const override;
|
||||
|
||||
bool IsInDepot() const
|
||||
bool IsInDepot() const override
|
||||
{
|
||||
assert(this->IsPrimaryVehicle());
|
||||
return (this->vehstatus & VS_HIDDEN) != 0 && IsHangarTile(this->tile);
|
||||
}
|
||||
|
||||
bool Tick();
|
||||
void OnNewDay();
|
||||
uint Crash(bool flooded = false);
|
||||
TileIndex GetOrderStationLocation(StationID station);
|
||||
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
|
||||
bool Tick() override;
|
||||
void OnNewCalendarDay() override;
|
||||
void OnNewEconomyDay() override;
|
||||
uint Crash(bool flooded = false) override;
|
||||
TileIndex GetOrderStationLocation(StationID station) override;
|
||||
ClosestDepot FindClosestDepot() override;
|
||||
|
||||
/**
|
||||
* Check if the aircraft type is a normal flying device; eg
|
||||
@@ -130,7 +131,7 @@ struct Aircraft FINAL : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
|
||||
* Get the range of this aircraft.
|
||||
* @return Range in tiles or 0 if unlimited range.
|
||||
*/
|
||||
uint16 GetRange() const
|
||||
uint16_t GetRange() const
|
||||
{
|
||||
return this->acache.cached_max_range;
|
||||
}
|
||||
@@ -139,5 +140,6 @@ struct Aircraft FINAL : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
|
||||
void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result);
|
||||
|
||||
Station *GetTargetAirportIfValid(const Aircraft *v);
|
||||
void HandleMissingAircraftOrders(Aircraft *v);
|
||||
|
||||
#endif /* AIRCRAFT_H */
|
||||
|
||||
+60
-50
@@ -17,10 +17,12 @@
|
||||
#include "newgrf_engine.h"
|
||||
#include "newgrf_sound.h"
|
||||
#include "spritecache.h"
|
||||
#include "error_func.h"
|
||||
#include "strings_func.h"
|
||||
#include "command_func.h"
|
||||
#include "window_func.h"
|
||||
#include "date_func.h"
|
||||
#include "timer/timer_game_calendar.h"
|
||||
#include "timer/timer_game_economy.h"
|
||||
#include "vehicle_func.h"
|
||||
#include "sound_func.h"
|
||||
#include "cheat_type.h"
|
||||
@@ -99,7 +101,7 @@ static const SpriteID _aircraft_sprite[] = {
|
||||
};
|
||||
|
||||
template <>
|
||||
bool IsValidImageIndex<VEH_AIRCRAFT>(uint8 image_index)
|
||||
bool IsValidImageIndex<VEH_AIRCRAFT>(uint8_t image_index)
|
||||
{
|
||||
return image_index < lengthof(_aircraft_sprite);
|
||||
}
|
||||
@@ -171,7 +173,7 @@ static StationID FindNearestHangar(const Aircraft *v)
|
||||
|
||||
void Aircraft::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
|
||||
{
|
||||
uint8 spritenum = this->spritenum;
|
||||
uint8_t spritenum = this->spritenum;
|
||||
|
||||
if (is_custom_sprite(spritenum)) {
|
||||
GetCustomVehicleSprite(this, direction, image_type, result);
|
||||
@@ -201,7 +203,7 @@ void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteS
|
||||
static void GetAircraftIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
|
||||
{
|
||||
const Engine *e = Engine::Get(engine);
|
||||
uint8 spritenum = e->u.air.image_index;
|
||||
uint8_t spritenum = e->u.air.image_index;
|
||||
|
||||
if (is_custom_sprite(spritenum)) {
|
||||
GetCustomVehicleIcon(engine, DIR_W, image_type, result);
|
||||
@@ -337,14 +339,15 @@ CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *
|
||||
|
||||
v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_aircraft);
|
||||
|
||||
v->date_of_last_service = _date;
|
||||
v->build_year = u->build_year = _cur_year;
|
||||
v->date_of_last_service = TimerGameEconomy::date;
|
||||
v->date_of_last_service_newgrf = TimerGameCalendar::date;
|
||||
v->build_year = u->build_year = TimerGameCalendar::year;
|
||||
|
||||
v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
|
||||
u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
|
||||
|
||||
v->random_bits = VehicleRandomBits();
|
||||
u->random_bits = VehicleRandomBits();
|
||||
v->random_bits = Random();
|
||||
u->random_bits = Random();
|
||||
|
||||
v->vehicle_flags = 0;
|
||||
if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
|
||||
@@ -374,7 +377,7 @@ CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *
|
||||
w->spritenum = 0xFF;
|
||||
w->subtype = AIR_ROTOR;
|
||||
w->sprite_cache.sprite_seq.Set(SPR_ROTOR_STOPPED);
|
||||
w->random_bits = VehicleRandomBits();
|
||||
w->random_bits = Random();
|
||||
/* Use rotor's air.state to store the rotor animation frame */
|
||||
w->state = HRS_ROTOR_STOPPED;
|
||||
w->UpdateDeltaXY();
|
||||
@@ -388,7 +391,7 @@ CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *
|
||||
}
|
||||
|
||||
|
||||
bool Aircraft::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
|
||||
ClosestDepot Aircraft::FindClosestDepot()
|
||||
{
|
||||
const Station *st = GetTargetAirportIfValid(this);
|
||||
/* If the station is not a valid airport or if it has no hangars */
|
||||
@@ -396,15 +399,12 @@ bool Aircraft::FindClosestDepot(TileIndex *location, DestinationID *destination,
|
||||
/* the aircraft has to search for a hangar on its own */
|
||||
StationID station = FindNearestHangar(this);
|
||||
|
||||
if (station == INVALID_STATION) return false;
|
||||
if (station == INVALID_STATION) return ClosestDepot();
|
||||
|
||||
st = Station::Get(station);
|
||||
}
|
||||
|
||||
if (location != nullptr) *location = st->xy;
|
||||
if (destination != nullptr) *destination = st->index;
|
||||
|
||||
return true;
|
||||
return ClosestDepot(st->xy, st->index);
|
||||
}
|
||||
|
||||
static void CheckIfAircraftNeedsService(Aircraft *v)
|
||||
@@ -440,7 +440,15 @@ Money Aircraft::GetRunningCost() const
|
||||
return GetPrice(PR_RUNNING_AIRCRAFT, cost_factor, e->GetGRF());
|
||||
}
|
||||
|
||||
void Aircraft::OnNewDay()
|
||||
/** Calendar day handler */
|
||||
void Aircraft::OnNewCalendarDay()
|
||||
{
|
||||
if (!this->IsNormalAircraft()) return;
|
||||
AgeVehicle(this);
|
||||
}
|
||||
|
||||
/** Economy day handler */
|
||||
void Aircraft::OnNewEconomyDay()
|
||||
{
|
||||
if (!this->IsNormalAircraft()) return;
|
||||
|
||||
@@ -449,12 +457,11 @@ void Aircraft::OnNewDay()
|
||||
CheckOrders(this);
|
||||
|
||||
CheckVehicleBreakdown(this);
|
||||
AgeVehicle(this);
|
||||
CheckIfAircraftNeedsService(this);
|
||||
|
||||
if (this->running_ticks == 0) return;
|
||||
|
||||
CommandCost cost(EXPENSES_AIRCRAFT_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
|
||||
CommandCost cost(EXPENSES_AIRCRAFT_RUN, this->GetRunningCost() * this->running_ticks / (CalendarTime::DAYS_IN_YEAR * Ticks::DAY_TICKS));
|
||||
|
||||
this->profit_this_year -= cost.GetCost();
|
||||
this->running_ticks = 0;
|
||||
@@ -532,12 +539,12 @@ void SetAircraftPosition(Aircraft *v, int x, int y, int z)
|
||||
|
||||
Aircraft *u = v->Next();
|
||||
|
||||
int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
|
||||
int safe_y = Clamp(y - 1, 0, MapMaxY() * TILE_SIZE);
|
||||
int safe_x = Clamp(x, 0, Map::MaxX() * TILE_SIZE);
|
||||
int safe_y = Clamp(y - 1, 0, Map::MaxY() * TILE_SIZE);
|
||||
u->x_pos = x;
|
||||
u->y_pos = y - ((v->z_pos - GetSlopePixelZ(safe_x, safe_y)) >> 3);
|
||||
|
||||
safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE);
|
||||
safe_y = Clamp(u->y_pos, 0, Map::MaxY() * TILE_SIZE);
|
||||
u->z_pos = GetSlopePixelZ(safe_x, safe_y);
|
||||
u->sprite_cache.sprite_seq.CopyWithoutPalette(v->sprite_cache.sprite_seq); // the shadow is never coloured
|
||||
|
||||
@@ -699,8 +706,8 @@ static int UpdateAircraftSpeed(Aircraft *v, uint speed_limit = SPEED_LIMIT_NONE,
|
||||
*/
|
||||
int GetTileHeightBelowAircraft(const Vehicle *v)
|
||||
{
|
||||
int safe_x = Clamp(v->x_pos, 0, MapMaxX() * TILE_SIZE);
|
||||
int safe_y = Clamp(v->y_pos, 0, MapMaxY() * TILE_SIZE);
|
||||
int safe_x = Clamp(v->x_pos, 0, Map::MaxX() * TILE_SIZE);
|
||||
int safe_y = Clamp(v->y_pos, 0, Map::MaxY() * TILE_SIZE);
|
||||
return TileHeight(TileVirtXY(safe_x, safe_y)) * TILE_HEIGHT;
|
||||
}
|
||||
|
||||
@@ -1167,7 +1174,7 @@ static bool HandleCrashedAircraft(Aircraft *v)
|
||||
|
||||
/* make aircraft crash down to the ground */
|
||||
if (v->crashed_counter < 500 && st == nullptr && ((v->crashed_counter % 3) == 0) ) {
|
||||
int z = GetSlopePixelZ(Clamp(v->x_pos, 0, MapMaxX() * TILE_SIZE), Clamp(v->y_pos, 0, MapMaxY() * TILE_SIZE));
|
||||
int z = GetSlopePixelZ(Clamp(v->x_pos, 0, Map::MaxX() * TILE_SIZE), Clamp(v->y_pos, 0, Map::MaxY() * TILE_SIZE));
|
||||
v->z_pos -= 1;
|
||||
if (v->z_pos == z) {
|
||||
v->crashed_counter = 500;
|
||||
@@ -1176,7 +1183,7 @@ static bool HandleCrashedAircraft(Aircraft *v)
|
||||
}
|
||||
|
||||
if (v->crashed_counter < 650) {
|
||||
uint32 r;
|
||||
uint32_t r;
|
||||
if (Chance16R(1, 32, r)) {
|
||||
static const DirDiff delta[] = {
|
||||
DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
|
||||
@@ -1220,8 +1227,8 @@ static bool HandleCrashedAircraft(Aircraft *v)
|
||||
static void HandleAircraftSmoke(Aircraft *v, bool mode)
|
||||
{
|
||||
static const struct {
|
||||
int8 x;
|
||||
int8 y;
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
} smoke_pos[] = {
|
||||
{ 5, 5 },
|
||||
{ 6, 0 },
|
||||
@@ -1283,7 +1290,7 @@ void HandleMissingAircraftOrders(Aircraft *v)
|
||||
}
|
||||
|
||||
|
||||
TileIndex Aircraft::GetOrderStationLocation(StationID station)
|
||||
TileIndex Aircraft::GetOrderStationLocation(StationID)
|
||||
{
|
||||
/* Orders are changed in flight, ensure going to the right station. */
|
||||
if (this->state == FLYING) {
|
||||
@@ -1327,14 +1334,12 @@ static void CrashAirplane(Aircraft *v)
|
||||
v->Next()->cargo.Truncate();
|
||||
const Station *st = GetTargetAirportIfValid(v);
|
||||
StringID newsitem;
|
||||
TileIndex vt;
|
||||
TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
|
||||
if (st == nullptr) {
|
||||
newsitem = STR_NEWS_PLANE_CRASH_OUT_OF_FUEL;
|
||||
vt = TileVirtXY(v->x_pos, v->y_pos);
|
||||
} else {
|
||||
SetDParam(1, st->index);
|
||||
newsitem = STR_NEWS_AIRCRAFT_CRASH;
|
||||
vt = v->tile;
|
||||
}
|
||||
|
||||
AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, vt, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING));
|
||||
@@ -1360,7 +1365,7 @@ static void MaybeCrashAirplane(Aircraft *v)
|
||||
|
||||
Station *st = Station::Get(v->targetairport);
|
||||
|
||||
uint32 prob;
|
||||
uint32_t prob;
|
||||
if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) &&
|
||||
(AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
|
||||
!_cheats.no_jetcrash.value) {
|
||||
@@ -1373,9 +1378,9 @@ static void MaybeCrashAirplane(Aircraft *v)
|
||||
if (GB(Random(), 0, 22) > prob) return;
|
||||
|
||||
/* Crash the airplane. Remove all goods stored at the station. */
|
||||
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
||||
st->goods[i].rating = 1;
|
||||
st->goods[i].cargo.Truncate();
|
||||
for (GoodsEntry &ge : st->goods) {
|
||||
ge.rating = 1;
|
||||
ge.cargo.Truncate();
|
||||
}
|
||||
|
||||
CrashAirplane(v);
|
||||
@@ -1472,6 +1477,7 @@ void AircraftLeaveHangar(Aircraft *v, Direction exit_dir)
|
||||
}
|
||||
|
||||
VehicleServiceInDepot(v);
|
||||
v->LeaveUnbunchingDepot();
|
||||
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
|
||||
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
|
||||
SetWindowClassesDirty(WC_AIRCRAFT_LIST);
|
||||
@@ -1516,6 +1522,9 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if we should wait here for unbunching. */
|
||||
if (v->IsWaitingForUnbunching()) return;
|
||||
|
||||
if (!v->current_order.IsType(OT_GOTO_STATION) &&
|
||||
!v->current_order.IsType(OT_GOTO_DEPOT))
|
||||
return;
|
||||
@@ -1558,7 +1567,8 @@ static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *
|
||||
if (_settings_game.order.serviceathelipad) {
|
||||
if (v->subtype == AIR_HELICOPTER && apc->num_helipads > 0) {
|
||||
/* an excerpt of ServiceAircraft, without the invisibility stuff */
|
||||
v->date_of_last_service = _date;
|
||||
v->date_of_last_service = TimerGameEconomy::date;
|
||||
v->date_of_last_service_newgrf = TimerGameCalendar::date;
|
||||
v->breakdowns_since_last_service = 0;
|
||||
v->reliability = v->GetEngine()->reliability;
|
||||
SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
|
||||
@@ -1589,7 +1599,7 @@ static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *
|
||||
return;
|
||||
default: // orders have been deleted (no orders), goto depot and don't bother us
|
||||
v->current_order.Free();
|
||||
go_to_hangar = Station::Get(v->targetairport)->airport.HasHangar();
|
||||
go_to_hangar = true;
|
||||
}
|
||||
|
||||
if (go_to_hangar && Station::Get(v->targetairport)->airport.HasHangar()) {
|
||||
@@ -1601,31 +1611,31 @@ static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *
|
||||
AirportMove(v, apc);
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_General(Aircraft *v, const AirportFTAClass *apc)
|
||||
static void AircraftEventHandler_General(Aircraft *, const AirportFTAClass *)
|
||||
{
|
||||
error("OK, you shouldn't be here, check your Airport Scheme!");
|
||||
FatalError("OK, you shouldn't be here, check your Airport Scheme!");
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_TakeOff(Aircraft *v, const AirportFTAClass *apc)
|
||||
static void AircraftEventHandler_TakeOff(Aircraft *v, const AirportFTAClass *)
|
||||
{
|
||||
PlayAircraftSound(v); // play takeoffsound for airplanes
|
||||
v->state = STARTTAKEOFF;
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_StartTakeOff(Aircraft *v, const AirportFTAClass *apc)
|
||||
static void AircraftEventHandler_StartTakeOff(Aircraft *v, const AirportFTAClass *)
|
||||
{
|
||||
v->state = ENDTAKEOFF;
|
||||
v->UpdateDeltaXY();
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_EndTakeOff(Aircraft *v, const AirportFTAClass *apc)
|
||||
static void AircraftEventHandler_EndTakeOff(Aircraft *v, const AirportFTAClass *)
|
||||
{
|
||||
v->state = FLYING;
|
||||
/* get the next position to go to, differs per airport */
|
||||
AircraftNextAirportPos_and_Order(v);
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass *apc)
|
||||
static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass *)
|
||||
{
|
||||
v->state = FLYING;
|
||||
v->UpdateDeltaXY();
|
||||
@@ -1657,8 +1667,8 @@ static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
|
||||
/* save speed before, since if AirportHasBlock is false, it resets them to 0
|
||||
* we don't want that for plane in air
|
||||
* hack for speed thingie */
|
||||
uint16 tcur_speed = v->cur_speed;
|
||||
uint16 tsubspeed = v->subspeed;
|
||||
uint16_t tcur_speed = v->cur_speed;
|
||||
uint16_t tsubspeed = v->subspeed;
|
||||
if (!AirportHasBlock(v, current, apc)) {
|
||||
v->state = landingtype; // LANDING / HELILANDING
|
||||
if (v->state == HELILANDING) SetBit(v->flags, VAF_HELI_DIRECT_DESCENT);
|
||||
@@ -1679,7 +1689,7 @@ static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
|
||||
v->pos = apc->layout[v->pos].next_position;
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *apc)
|
||||
static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *)
|
||||
{
|
||||
v->state = ENDLANDING;
|
||||
AircraftLandAirplane(v); // maybe crash airplane
|
||||
@@ -1692,7 +1702,7 @@ static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *apc
|
||||
}
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_HeliLanding(Aircraft *v, const AirportFTAClass *apc)
|
||||
static void AircraftEventHandler_HeliLanding(Aircraft *v, const AirportFTAClass *)
|
||||
{
|
||||
v->state = HELIENDLANDING;
|
||||
v->UpdateDeltaXY();
|
||||
@@ -1842,7 +1852,7 @@ static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const Ai
|
||||
/* same block, then of course we can move */
|
||||
if (apc->layout[current_pos->position].block != next->block) {
|
||||
const Station *st = Station::Get(v->targetairport);
|
||||
uint64 airport_flags = next->block;
|
||||
uint64_t airport_flags = next->block;
|
||||
|
||||
/* check additional possible extra blocks */
|
||||
if (current_pos != reference && current_pos->block != NOTHING_block) {
|
||||
@@ -1872,7 +1882,7 @@ static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const A
|
||||
|
||||
/* if the next position is in another block, check it and wait until it is free */
|
||||
if ((apc->layout[current_pos->position].block & next->block) != next->block) {
|
||||
uint64 airport_flags = next->block;
|
||||
uint64_t airport_flags = next->block;
|
||||
/* search for all all elements in the list with the same state, and blocks != N
|
||||
* this means more blocks should be checked/set */
|
||||
const AirportFTA *current = current_pos;
|
||||
@@ -1909,7 +1919,7 @@ static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const A
|
||||
*/
|
||||
struct MovementTerminalMapping {
|
||||
AirportMovementStates state; ///< Aircraft movement state when going to this terminal.
|
||||
uint64 airport_flag; ///< Bitmask in the airport flags that need to be free for this terminal.
|
||||
uint64_t airport_flag; ///< Bitmask in the airport flags that need to be free for this terminal.
|
||||
};
|
||||
|
||||
/** A list of all valid terminals and their associated blocks. */
|
||||
|
||||
@@ -38,7 +38,7 @@ void DrawAircraftDetails(const Aircraft *v, const Rect &r)
|
||||
SetDParam(1, u->build_year);
|
||||
SetDParam(2, u->value);
|
||||
DrawString(r.left, r.right, y, STR_VEHICLE_INFO_BUILT_VALUE);
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
y += GetCharacterHeight(FS_NORMAL);
|
||||
|
||||
SetDParam(0, u->cargo_type);
|
||||
SetDParam(1, u->cargo_cap);
|
||||
@@ -46,7 +46,7 @@ void DrawAircraftDetails(const Aircraft *v, const Rect &r)
|
||||
SetDParam(3, u->Next()->cargo_cap);
|
||||
SetDParam(4, GetCargoSubtypeText(u));
|
||||
DrawString(r.left, r.right, y, (u->Next()->cargo_cap != 0) ? STR_VEHICLE_INFO_CAPACITY_CAPACITY : STR_VEHICLE_INFO_CAPACITY);
|
||||
y += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_normal;
|
||||
y += GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
|
||||
}
|
||||
|
||||
if (u->cargo_cap != 0) {
|
||||
@@ -56,10 +56,10 @@ void DrawAircraftDetails(const Aircraft *v, const Rect &r)
|
||||
/* Cargo names (fix pluralness) */
|
||||
SetDParam(0, u->cargo_type);
|
||||
SetDParam(1, cargo_count);
|
||||
SetDParam(2, u->cargo.Source());
|
||||
SetDParam(2, u->cargo.GetFirstStation());
|
||||
DrawString(r.left, r.right, y, STR_VEHICLE_DETAILS_CARGO_FROM);
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
feeder_share += u->cargo.FeederShare();
|
||||
y += GetCharacterHeight(FS_NORMAL);
|
||||
feeder_share += u->cargo.GetFeederShare();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -65,7 +65,7 @@ AIRPORT_GENERIC(dummy, nullptr, 0, AirportFTAClass::ALL, 0)
|
||||
#include "table/airport_defaults.h"
|
||||
|
||||
|
||||
static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA);
|
||||
static uint16_t AirportGetNofElements(const AirportFTAbuildup *apFA);
|
||||
static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA);
|
||||
|
||||
|
||||
@@ -147,9 +147,9 @@ AirportFTAClass::~AirportFTAClass()
|
||||
* Since it is actually just a big array of AirportFTA types, we only
|
||||
* know one element from the other by differing 'position' identifiers
|
||||
*/
|
||||
static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
|
||||
static uint16_t AirportGetNofElements(const AirportFTAbuildup *apFA)
|
||||
{
|
||||
uint16 nofelements = 0;
|
||||
uint16_t nofelements = 0;
|
||||
int temp = apFA[0].position;
|
||||
|
||||
for (uint i = 0; i < MAX_ELEMENTS; i++) {
|
||||
@@ -171,7 +171,7 @@ static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
|
||||
static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA)
|
||||
{
|
||||
AirportFTA *FAutomata = MallocT<AirportFTA>(nofelements);
|
||||
uint16 internalcounter = 0;
|
||||
uint16_t internalcounter = 0;
|
||||
|
||||
for (uint i = 0; i < nofelements; i++) {
|
||||
AirportFTA *current = &FAutomata[i];
|
||||
|
||||
+5
-5
@@ -85,7 +85,7 @@ enum AirportMovementStates {
|
||||
};
|
||||
|
||||
/** Movement Blocks on Airports blocks (eg_airport_flags). */
|
||||
static const uint64
|
||||
static const uint64_t
|
||||
TERM1_block = 1ULL << 0, ///< Block belonging to terminal 1.
|
||||
TERM2_block = 1ULL << 1, ///< Block belonging to terminal 2.
|
||||
TERM3_block = 1ULL << 2, ///< Block belonging to terminal 3.
|
||||
@@ -129,9 +129,9 @@ static const uint64
|
||||
|
||||
/** A single location on an airport where aircraft can move to. */
|
||||
struct AirportMovingData {
|
||||
int16 x; ///< x-coordinate of the destination.
|
||||
int16 y; ///< y-coordinate of the destination.
|
||||
uint16 flag; ///< special flags when moving towards the destination.
|
||||
int16_t x; ///< x-coordinate of the destination.
|
||||
int16_t y; ///< y-coordinate of the destination.
|
||||
uint16_t flag; ///< special flags when moving towards the destination.
|
||||
Direction direction; ///< Direction to turn the aircraft after reaching the destination.
|
||||
};
|
||||
|
||||
@@ -189,7 +189,7 @@ DECLARE_ENUM_AS_BIT_SET(AirportFTAClass::Flags)
|
||||
/** Internal structure used in openttd - Finite sTate mAchine --> FTA */
|
||||
struct AirportFTA {
|
||||
AirportFTA *next; ///< possible extra movement choices from this position
|
||||
uint64 block; ///< 64 bit blocks (st->airport.flags), should be enough for the most complex airports
|
||||
uint64_t block; ///< 64 bit blocks (st->airport.flags), should be enough for the most complex airports
|
||||
byte position; ///< the position that an airplane is at
|
||||
byte next_position; ///< next position from this position
|
||||
byte heading; ///< heading (current orders), guiding an airplane to its target on an airport
|
||||
|
||||
+92
-94
@@ -31,6 +31,8 @@
|
||||
#include "airport_cmd.h"
|
||||
#include "station_cmd.h"
|
||||
#include "zoom_func.h"
|
||||
#include "timer/timer.h"
|
||||
#include "timer/timer_game_calendar.h"
|
||||
|
||||
#include "widgets/airport_widget.h"
|
||||
|
||||
@@ -45,7 +47,7 @@ static void ShowBuildAirportPicker(Window *parent);
|
||||
|
||||
SpriteID GetCustomAirportSprite(const AirportSpec *as, byte layout);
|
||||
|
||||
void CcBuildAirport(Commands cmd, const CommandCost &result, TileIndex tile)
|
||||
void CcBuildAirport(Commands, const CommandCost &result, TileIndex tile)
|
||||
{
|
||||
if (result.Failed()) return;
|
||||
|
||||
@@ -85,10 +87,10 @@ struct BuildAirToolbarWindow : Window {
|
||||
this->InitNested(window_number);
|
||||
this->OnInvalidateData();
|
||||
if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this);
|
||||
this->last_user_action = WIDGET_LIST_END;
|
||||
this->last_user_action = INVALID_WID_AT;
|
||||
}
|
||||
|
||||
void Close() override
|
||||
void Close([[maybe_unused]] int data = 0) override
|
||||
{
|
||||
if (this->IsWidgetLowered(WID_AT_AIRPORT)) SetViewportCatchmentStation(nullptr, true);
|
||||
if (_settings_client.gui.link_terraform_toolbar) CloseWindowById(WC_SCEN_LAND_GEN, 0, false);
|
||||
@@ -100,14 +102,12 @@ struct BuildAirToolbarWindow : Window {
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
|
||||
{
|
||||
if (!gui_scope) return;
|
||||
|
||||
bool can_build = CanBuildVehicleInfrastructure(VEH_AIRCRAFT);
|
||||
this->SetWidgetsDisabledState(!can_build,
|
||||
WID_AT_AIRPORT,
|
||||
WIDGET_LIST_END);
|
||||
this->SetWidgetDisabledState(WID_AT_AIRPORT, !can_build);
|
||||
if (!can_build) {
|
||||
CloseWindowById(WC_BUILD_STATION, TRANSPORT_AIR);
|
||||
|
||||
@@ -118,7 +118,7 @@ struct BuildAirToolbarWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AT_AIRPORT:
|
||||
@@ -138,7 +138,7 @@ struct BuildAirToolbarWindow : Window {
|
||||
}
|
||||
|
||||
|
||||
void OnPlaceObject(Point pt, TileIndex tile) override
|
||||
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
|
||||
{
|
||||
switch (this->last_user_action) {
|
||||
case WID_AT_AIRPORT:
|
||||
@@ -153,12 +153,12 @@ struct BuildAirToolbarWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override
|
||||
void OnPlaceDrag(ViewportPlaceMethod select_method, [[maybe_unused]] ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt) override
|
||||
{
|
||||
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
|
||||
}
|
||||
|
||||
void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override
|
||||
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
|
||||
{
|
||||
if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) {
|
||||
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
|
||||
@@ -175,30 +175,26 @@ struct BuildAirToolbarWindow : Window {
|
||||
CloseWindowById(WC_SELECT_STATION, 0);
|
||||
}
|
||||
|
||||
static HotkeyList hotkeys;
|
||||
/**
|
||||
* Handler for global hotkeys of the BuildAirToolbarWindow.
|
||||
* @param hotkey Hotkey
|
||||
* @return ES_HANDLED if hotkey was accepted.
|
||||
*/
|
||||
static EventState AirportToolbarGlobalHotkeys(int hotkey)
|
||||
{
|
||||
if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED;
|
||||
Window *w = ShowBuildAirToolbar();
|
||||
if (w == nullptr) return ES_NOT_HANDLED;
|
||||
return w->OnHotkey(hotkey);
|
||||
}
|
||||
|
||||
static inline HotkeyList hotkeys{"airtoolbar", {
|
||||
Hotkey('1', "airport", WID_AT_AIRPORT),
|
||||
Hotkey('2', "demolish", WID_AT_DEMOLISH),
|
||||
}, AirportToolbarGlobalHotkeys};
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for global hotkeys of the BuildAirToolbarWindow.
|
||||
* @param hotkey Hotkey
|
||||
* @return ES_HANDLED if hotkey was accepted.
|
||||
*/
|
||||
static EventState AirportToolbarGlobalHotkeys(int hotkey)
|
||||
{
|
||||
if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED;
|
||||
Window *w = ShowBuildAirToolbar();
|
||||
if (w == nullptr) return ES_NOT_HANDLED;
|
||||
return w->OnHotkey(hotkey);
|
||||
}
|
||||
|
||||
static Hotkey airtoolbar_hotkeys[] = {
|
||||
Hotkey('1', "airport", WID_AT_AIRPORT),
|
||||
Hotkey('2', "demolish", WID_AT_DEMOLISH),
|
||||
HOTKEY_LIST_END
|
||||
};
|
||||
HotkeyList BuildAirToolbarWindow::hotkeys("airtoolbar", airtoolbar_hotkeys, AirportToolbarGlobalHotkeys);
|
||||
|
||||
static const NWidgetPart _nested_air_toolbar_widgets[] = {
|
||||
static constexpr NWidgetPart _nested_air_toolbar_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
@@ -211,11 +207,11 @@ static const NWidgetPart _nested_air_toolbar_widgets[] = {
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _air_toolbar_desc(
|
||||
static WindowDesc _air_toolbar_desc(__FILE__, __LINE__,
|
||||
WDP_ALIGN_TOOLBAR, "toolbar_air", 0, 0,
|
||||
WC_BUILD_TOOLBAR, WC_NONE,
|
||||
WDF_CONSTRUCTION,
|
||||
_nested_air_toolbar_widgets, lengthof(_nested_air_toolbar_widgets),
|
||||
std::begin(_nested_air_toolbar_widgets), std::end(_nested_air_toolbar_widgets),
|
||||
&BuildAirToolbarWindow::hotkeys
|
||||
);
|
||||
|
||||
@@ -245,7 +241,7 @@ class BuildAirportWindow : public PickerWindowBase {
|
||||
DropDownList list;
|
||||
|
||||
for (uint i = 0; i < AirportClass::GetClassCount(); i++) {
|
||||
list.emplace_back(new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false));
|
||||
list.push_back(std::make_unique<DropDownListStringItem>(AirportClass::Get((AirportClassID)i)->name, i, false));
|
||||
}
|
||||
|
||||
return list;
|
||||
@@ -289,13 +285,13 @@ public:
|
||||
if (selectFirstAirport) this->SelectFirstAvailableAirport(true);
|
||||
}
|
||||
|
||||
void Close() override
|
||||
void Close([[maybe_unused]] int data = 0) override
|
||||
{
|
||||
CloseWindowById(WC_SELECT_STATION, 0);
|
||||
this->PickerWindowBase::Close();
|
||||
}
|
||||
|
||||
void SetStringParameters(int widget) const override
|
||||
void SetStringParameters(WidgetID widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AP_CLASS_DROPDOWN:
|
||||
@@ -320,14 +316,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AP_CLASS_DROPDOWN: {
|
||||
Dimension d = {0, 0};
|
||||
for (uint i = 0; i < AirportClass::GetClassCount(); i++) {
|
||||
SetDParam(0, AirportClass::Get((AirportClassID)i)->name);
|
||||
d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING));
|
||||
d = maxdim(d, GetStringBoundingBox(AirportClass::Get((AirportClassID)i)->name));
|
||||
}
|
||||
d.width += padding.width;
|
||||
d.height += padding.height;
|
||||
@@ -343,7 +338,7 @@ public:
|
||||
size->width = std::max(size->width, GetStringBoundingBox(as->name).width + padding.width);
|
||||
}
|
||||
|
||||
this->line_height = FONT_HEIGHT_NORMAL + padding.height;
|
||||
this->line_height = GetCharacterHeight(FS_NORMAL) + padding.height;
|
||||
size->height = 5 * this->line_height;
|
||||
break;
|
||||
}
|
||||
@@ -372,9 +367,7 @@ public:
|
||||
StringID string = GetAirportTextCallback(as, layout, CBID_AIRPORT_ADDITIONAL_TEXT);
|
||||
if (string == STR_UNDEFINED) continue;
|
||||
|
||||
/* STR_BLACK_STRING is used to start the string with {BLACK} */
|
||||
SetDParam(0, string);
|
||||
Dimension d = GetStringMultiLineBoundingBox(STR_BLACK_STRING, *size);
|
||||
Dimension d = GetStringMultiLineBoundingBox(string, *size);
|
||||
*size = maxdim(d, *size);
|
||||
}
|
||||
}
|
||||
@@ -384,7 +377,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AP_AIRPORT_LIST: {
|
||||
@@ -415,8 +408,7 @@ public:
|
||||
const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index);
|
||||
StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_ADDITIONAL_TEXT);
|
||||
if (string != STR_UNDEFINED) {
|
||||
SetDParam(0, string);
|
||||
DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BLACK_STRING);
|
||||
DrawStringMultiLine(r.left, r.right, r.top, r.bottom, string, TC_BLACK);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -428,7 +420,7 @@ public:
|
||||
this->DrawWidgets();
|
||||
|
||||
Rect r = this->GetWidget<NWidgetBase>(WID_AP_ACCEPTANCE)->GetCurrentRect();
|
||||
int top = r.top + WidgetDimensions::scaled.vsep_normal;
|
||||
int top = r.top;
|
||||
|
||||
if (_selected_airport_index != -1) {
|
||||
const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index);
|
||||
@@ -439,19 +431,19 @@ public:
|
||||
/* show the noise of the selected airport */
|
||||
SetDParam(0, as->noise_level);
|
||||
DrawString(r.left, r.right, top, STR_STATION_BUILD_NOISE);
|
||||
top += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_normal;
|
||||
top += GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
|
||||
}
|
||||
|
||||
if (_settings_game.economy.infrastructure_maintenance) {
|
||||
Money monthly = _price[PR_INFRASTRUCTURE_AIRPORT] * as->maintenance_cost >> 3;
|
||||
SetDParam(0, monthly * 12);
|
||||
DrawString(r.left, r.right, top, STR_STATION_BUILD_INFRASTRUCTURE_COST);
|
||||
top += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_normal;
|
||||
DrawString(r.left, r.right, top, TimerGameEconomy::UsingWallclockUnits() ? STR_STATION_BUILD_INFRASTRUCTURE_COST_PERIOD : STR_STATION_BUILD_INFRASTRUCTURE_COST_YEAR);
|
||||
top += GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
|
||||
}
|
||||
|
||||
/* strings such as 'Size' and 'Coverage Area' */
|
||||
top = DrawStationCoverageAreaText(r.left, r.right, top, SCT_ALL, rad, false) + WidgetDimensions::scaled.vsep_normal;
|
||||
top = DrawStationCoverageAreaText(r.left, r.right, top, SCT_ALL, rad, true) + WidgetDimensions::scaled.vsep_normal;
|
||||
top = DrawStationCoverageAreaText(r.left, r.right, top, SCT_ALL, rad, true);
|
||||
}
|
||||
|
||||
/* Resize background if the window is too small.
|
||||
@@ -495,7 +487,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AP_CLASS_DROPDOWN:
|
||||
@@ -503,8 +495,8 @@ public:
|
||||
break;
|
||||
|
||||
case WID_AP_AIRPORT_LIST: {
|
||||
int num_clicked = this->vscroll->GetPosition() + (pt.y - this->GetWidget<NWidgetBase>(widget)->pos_y) / this->line_height;
|
||||
if (num_clicked >= this->vscroll->GetCount()) break;
|
||||
int num_clicked = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget, 0, this->line_height);
|
||||
if (num_clicked == INT_MAX) break;
|
||||
const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked);
|
||||
if (as->IsAvailable()) this->SelectOtherAirport(num_clicked);
|
||||
break;
|
||||
@@ -552,13 +544,14 @@ public:
|
||||
}
|
||||
if (change_class) {
|
||||
/* If that fails, select the first available airport
|
||||
* from a random class. */
|
||||
* from the first class where airports are available. */
|
||||
for (AirportClassID j = APC_BEGIN; j < APC_MAX; j++) {
|
||||
AirportClass *apclass = AirportClass::Get(j);
|
||||
for (uint i = 0; i < apclass->GetSpecCount(); i++) {
|
||||
const AirportSpec *as = apclass->GetSpec(i);
|
||||
if (as->IsAvailable()) {
|
||||
_selected_airport_class = j;
|
||||
this->vscroll->SetCount(apclass->GetSpecCount());
|
||||
this->SelectOtherAirport(i);
|
||||
return;
|
||||
}
|
||||
@@ -569,62 +562,67 @@ public:
|
||||
this->SelectOtherAirport(-1);
|
||||
}
|
||||
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
void OnDropdownSelect(WidgetID widget, int index) override
|
||||
{
|
||||
assert(widget == WID_AP_CLASS_DROPDOWN);
|
||||
_selected_airport_class = (AirportClassID)index;
|
||||
this->vscroll->SetCount(AirportClass::Get(_selected_airport_class)->GetSpecCount());
|
||||
this->SelectFirstAvailableAirport(false);
|
||||
if (widget == WID_AP_CLASS_DROPDOWN) {
|
||||
_selected_airport_class = (AirportClassID)index;
|
||||
this->vscroll->SetCount(AirportClass::Get(_selected_airport_class)->GetSpecCount());
|
||||
this->SelectFirstAvailableAirport(false);
|
||||
}
|
||||
}
|
||||
|
||||
void OnRealtimeTick(uint delta_ms) override
|
||||
void OnRealtimeTick([[maybe_unused]] uint delta_ms) override
|
||||
{
|
||||
CheckRedrawStationCoverage(this);
|
||||
}
|
||||
|
||||
IntervalTimer<TimerGameCalendar> yearly_interval = {{TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE}, [this](auto) {
|
||||
this->InvalidateData();
|
||||
}};
|
||||
};
|
||||
|
||||
static const NWidgetPart _nested_build_airport_widgets[] = {
|
||||
static constexpr NWidgetPart _nested_build_airport_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2),
|
||||
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP),
|
||||
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL),
|
||||
NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NULL),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL),
|
||||
EndContainer(),
|
||||
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0),
|
||||
EndContainer(),
|
||||
/* Bottom panel. */
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_AP_BOTTOMPANEL),
|
||||
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetPadding(WidgetDimensions::unscaled.framerect), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), SetPadding(WidgetDimensions::unscaled.picker),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_picker, 0),
|
||||
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP),
|
||||
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR),
|
||||
EndContainer(),
|
||||
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetFill(1, 0),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL),
|
||||
NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING1, STR_NULL),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL),
|
||||
EndContainer(),
|
||||
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0),
|
||||
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0),
|
||||
NWidget(NWID_HORIZONTAL), SetPIP(14, 0, 14), SetPIPRatio(1, 0, 1),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0),
|
||||
SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0),
|
||||
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_ACCEPTANCE), SetResize(0, 1), SetFill(1, 0), SetMinimalTextLines(2, WidgetDimensions::unscaled.vsep_normal),
|
||||
EndContainer(),
|
||||
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_ACCEPTANCE), SetPadding(WidgetDimensions::unscaled.framerect), SetResize(0, 1), SetFill(1, 0),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _build_airport_desc(
|
||||
WDP_AUTO, "build_station_air", 0, 0,
|
||||
static WindowDesc _build_airport_desc(__FILE__, __LINE__,
|
||||
WDP_AUTO, nullptr, 0, 0,
|
||||
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
|
||||
WDF_CONSTRUCTION,
|
||||
_nested_build_airport_widgets, lengthof(_nested_build_airport_widgets)
|
||||
std::begin(_nested_build_airport_widgets), std::end(_nested_build_airport_widgets)
|
||||
);
|
||||
|
||||
static void ShowBuildAirportPicker(Window *parent)
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
/** @file animated_tile.cpp Everything related to animated tiles. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "core/alloc_func.hpp"
|
||||
#include "core/smallvec_type.hpp"
|
||||
#include "core/container_func.hpp"
|
||||
#include "tile_cmd.h"
|
||||
#include "viewport_func.h"
|
||||
#include "framerate_type.h"
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
/** @file articulated_vehicles.cpp Implementation of articulated vehicles. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "core/random_func.hpp"
|
||||
#include "train.h"
|
||||
#include "roadveh.h"
|
||||
#include "vehicle_func.h"
|
||||
@@ -35,7 +37,7 @@ static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle
|
||||
|
||||
const Engine *front_engine = Engine::Get(front_type);
|
||||
|
||||
uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, index, 0, front_type, front);
|
||||
uint16_t callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, index, 0, front_type, front);
|
||||
if (callback == CALLBACK_FAILED) return INVALID_ENGINE;
|
||||
|
||||
if (front_engine->GetGRF()->grf_version < 8) {
|
||||
@@ -102,12 +104,12 @@ uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
|
||||
* @param cargo_type returns the default cargo type, if needed
|
||||
* @return capacity
|
||||
*/
|
||||
static inline uint16 GetVehicleDefaultCapacity(EngineID engine, CargoID *cargo_type)
|
||||
static inline uint16_t GetVehicleDefaultCapacity(EngineID engine, CargoID *cargo_type)
|
||||
{
|
||||
const Engine *e = Engine::Get(engine);
|
||||
CargoID cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID);
|
||||
CargoID cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : INVALID_CARGO);
|
||||
if (cargo_type != nullptr) *cargo_type = cargo;
|
||||
if (cargo == CT_INVALID) return 0;
|
||||
if (!IsValidCargoID(cargo)) return 0;
|
||||
return e->GetDisplayDefaultCapacity();
|
||||
}
|
||||
|
||||
@@ -138,11 +140,11 @@ static inline CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool inc
|
||||
*/
|
||||
CargoArray GetCapacityOfArticulatedParts(EngineID engine)
|
||||
{
|
||||
CargoArray capacity;
|
||||
CargoArray capacity{};
|
||||
const Engine *e = Engine::Get(engine);
|
||||
|
||||
CargoID cargo_type;
|
||||
uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type);
|
||||
uint16_t cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type);
|
||||
if (cargo_type < NUM_CARGO) capacity[cargo_type] = cargo_capacity;
|
||||
|
||||
if (!e->IsGroundVehicle()) return capacity;
|
||||
@@ -160,6 +162,35 @@ CargoArray GetCapacityOfArticulatedParts(EngineID engine)
|
||||
return capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cargo mask of the parts of a given engine.
|
||||
* @param engine The engine to get the capacities from.
|
||||
* @return The cargo mask.
|
||||
*/
|
||||
CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine)
|
||||
{
|
||||
CargoTypes cargoes = 0;
|
||||
const Engine *e = Engine::Get(engine);
|
||||
|
||||
CargoID cargo_type;
|
||||
uint16_t cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type);
|
||||
if (cargo_type < NUM_CARGO && cargo_capacity > 0) SetBit(cargoes, cargo_type);
|
||||
|
||||
if (!e->IsGroundVehicle()) return cargoes;
|
||||
|
||||
if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return cargoes;
|
||||
|
||||
for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
|
||||
EngineID artic_engine = GetNextArticulatedPart(i, engine);
|
||||
if (artic_engine == INVALID_ENGINE) break;
|
||||
|
||||
cargo_capacity = GetVehicleDefaultCapacity(artic_engine, &cargo_type);
|
||||
if (cargo_type < NUM_CARGO && cargo_capacity > 0) SetBit(cargoes, cargo_type);
|
||||
}
|
||||
|
||||
return cargoes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether any of the articulated parts is refittable
|
||||
* @param engine the first part
|
||||
@@ -225,36 +256,26 @@ CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial
|
||||
}
|
||||
|
||||
/**
|
||||
* Ands the refit_masks of all articulated parts.
|
||||
* @param engine the first part
|
||||
* @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask
|
||||
* @return bit mask of CargoIDs which are a refit option for every articulated part (with default capacity > 0)
|
||||
*/
|
||||
CargoTypes GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
|
||||
{
|
||||
CargoTypes union_mask, intersection_mask;
|
||||
GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask);
|
||||
return intersection_mask;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests if all parts of an articulated vehicle are refitted to the same cargo.
|
||||
* Get cargo mask of all cargoes carried by an articulated vehicle.
|
||||
* Note: Vehicles not carrying anything are ignored
|
||||
* @param v the first vehicle in the chain
|
||||
* @param cargo_type returns the common CargoID if needed. (CT_INVALID if no part is carrying something or they are carrying different things)
|
||||
* @return true if some parts are carrying different cargoes, false if all parts are carrying the same (nothing is also the same)
|
||||
* @param cargo_type returns the common CargoID if needed. (INVALID_CARGO if no part is carrying something or they are carrying different things)
|
||||
* @return cargo mask, may be 0 if the no vehicle parts have cargo capacity
|
||||
*/
|
||||
bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *cargo_type)
|
||||
CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoID *cargo_type)
|
||||
{
|
||||
CargoID first_cargo = CT_INVALID;
|
||||
CargoTypes cargoes = 0;
|
||||
CargoID first_cargo = INVALID_CARGO;
|
||||
|
||||
do {
|
||||
if (v->cargo_type != CT_INVALID && v->GetEngine()->CanCarryCargo()) {
|
||||
if (first_cargo == CT_INVALID) first_cargo = v->cargo_type;
|
||||
if (IsValidCargoID(v->cargo_type) && v->GetEngine()->CanCarryCargo()) {
|
||||
SetBit(cargoes, v->cargo_type);
|
||||
if (!IsValidCargoID(first_cargo)) first_cargo = v->cargo_type;
|
||||
if (first_cargo != v->cargo_type) {
|
||||
if (cargo_type != nullptr) *cargo_type = CT_INVALID;
|
||||
return true;
|
||||
if (cargo_type != nullptr) {
|
||||
*cargo_type = INVALID_CARGO;
|
||||
cargo_type = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +283,7 @@ bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *car
|
||||
} while (v != nullptr);
|
||||
|
||||
if (cargo_type != nullptr) *cargo_type = first_cargo;
|
||||
return false;
|
||||
return cargoes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,7 +304,7 @@ void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
|
||||
|
||||
CargoTypes real_refit_union = 0;
|
||||
CargoTypes real_refit_intersection = ALL_CARGOTYPES;
|
||||
CargoArray real_default_capacity;
|
||||
CargoTypes real_default_cargoes = 0;
|
||||
|
||||
do {
|
||||
CargoTypes refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true);
|
||||
@@ -291,15 +312,15 @@ void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
|
||||
if (refit_mask != 0) real_refit_intersection &= refit_mask;
|
||||
|
||||
assert(v->cargo_type < NUM_CARGO);
|
||||
real_default_capacity[v->cargo_type] += v->cargo_cap;
|
||||
if (v->cargo_cap > 0) SetBit(real_default_cargoes, v->cargo_type);
|
||||
|
||||
v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr;
|
||||
} while (v != nullptr);
|
||||
|
||||
/* Check whether the vehicle carries more cargoes than expected */
|
||||
bool carries_more = false;
|
||||
for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
|
||||
if (real_default_capacity[cid] != 0 && purchase_default_capacity[cid] == 0) {
|
||||
for (CargoID cid : SetCargoBitIterator(real_default_cargoes)) {
|
||||
if (purchase_default_capacity[cid] == 0) {
|
||||
carries_more = true;
|
||||
break;
|
||||
}
|
||||
@@ -397,6 +418,7 @@ void AddArticulatedParts(Vehicle *first)
|
||||
v->y_pos = first->y_pos;
|
||||
v->z_pos = first->z_pos;
|
||||
v->date_of_last_service = first->date_of_last_service;
|
||||
v->date_of_last_service_newgrf = first->date_of_last_service_newgrf;
|
||||
v->build_year = first->build_year;
|
||||
v->vehstatus = first->vehstatus & ~VS_STOPPED;
|
||||
|
||||
@@ -405,10 +427,11 @@ void AddArticulatedParts(Vehicle *first)
|
||||
v->engine_type = engine_type;
|
||||
v->value = 0;
|
||||
v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
|
||||
v->random_bits = VehicleRandomBits();
|
||||
v->random_bits = Random();
|
||||
|
||||
if (flip_image) v->spritenum++;
|
||||
|
||||
if (v->type == VEH_TRAIN && TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) SetBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION);
|
||||
v->UpdatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
|
||||
uint CountArticulatedParts(EngineID engine_type, bool purchase_window);
|
||||
CargoArray GetCapacityOfArticulatedParts(EngineID engine);
|
||||
CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine);
|
||||
void AddArticulatedParts(Vehicle *first);
|
||||
void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, CargoTypes *union_mask, CargoTypes *intersection_mask);
|
||||
CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type);
|
||||
CargoTypes GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type);
|
||||
bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *cargo_type);
|
||||
CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoID *cargo_type);
|
||||
bool IsArticulatedVehicleRefittable(EngineID engine);
|
||||
bool IsArticulatedEngine(EngineID engine_type);
|
||||
void CheckConsistencyOfArticulatedVehicle(const Vehicle *v);
|
||||
|
||||
+12
-1
@@ -69,7 +69,18 @@ EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group,
|
||||
/* We didn't find anything useful in the vehicle's own group so we will try ALL_GROUP */
|
||||
er = GetEngineReplacement(erl, engine, ALL_GROUP);
|
||||
}
|
||||
if (replace_when_old != nullptr) *replace_when_old = er == nullptr ? false : er->replace_when_old;
|
||||
if (replace_when_old != nullptr) {
|
||||
if (er == nullptr) {
|
||||
/* Not replacing */
|
||||
*replace_when_old = false;
|
||||
} else if (er->to == engine) {
|
||||
/* When replacing with same model, only ever do it when old */
|
||||
*replace_when_old = true;
|
||||
} else {
|
||||
/* Use player setting */
|
||||
*replace_when_old = er->replace_when_old;
|
||||
}
|
||||
}
|
||||
return er == nullptr ? INVALID_ENGINE : er->to;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "engine_type.h"
|
||||
#include "group_type.h"
|
||||
|
||||
typedef uint16 EngineRenewID;
|
||||
typedef uint16_t EngineRenewID;
|
||||
|
||||
/**
|
||||
* Memory pool for engine renew elements. DO NOT USE outside of engine.c. Is
|
||||
|
||||
+74
-66
@@ -16,6 +16,7 @@
|
||||
#include "autoreplace_func.h"
|
||||
#include "autoreplace_gui.h"
|
||||
#include "articulated_vehicles.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "core/random_func.hpp"
|
||||
#include "vehiclelist.h"
|
||||
#include "road.h"
|
||||
@@ -60,9 +61,6 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company)
|
||||
{
|
||||
assert(Engine::IsValidID(from) && Engine::IsValidID(to));
|
||||
|
||||
/* we can't replace an engine into itself (that would be autorenew) */
|
||||
if (from == to) return false;
|
||||
|
||||
const Engine *e_from = Engine::Get(from);
|
||||
const Engine *e_to = Engine::Get(to);
|
||||
VehicleType type = e_from->type;
|
||||
@@ -228,23 +226,31 @@ static int GetIncompatibleRefitOrderIdForAutoreplace(const Vehicle *v, EngineID
|
||||
* @param engine_type The EngineID of the vehicle that is being replaced to
|
||||
* @param part_of_chain The vehicle is part of a train
|
||||
* @return The cargo type to replace to
|
||||
* CT_NO_REFIT is returned if no refit is needed
|
||||
* CT_INVALID is returned when both old and new vehicle got cargo capacity and refitting the new one to the old one's cargo type isn't possible
|
||||
* CARGO_NO_REFIT is returned if no refit is needed
|
||||
* INVALID_CARGO is returned when both old and new vehicle got cargo capacity and refitting the new one to the old one's cargo type isn't possible
|
||||
*/
|
||||
static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, bool part_of_chain)
|
||||
{
|
||||
CargoTypes available_cargo_types, union_mask;
|
||||
GetArticulatedRefitMasks(engine_type, true, &union_mask, &available_cargo_types);
|
||||
|
||||
if (union_mask == 0) return CT_NO_REFIT; // Don't try to refit an engine with no cargo capacity
|
||||
if (union_mask == 0) return CARGO_NO_REFIT; // Don't try to refit an engine with no cargo capacity
|
||||
|
||||
CargoID cargo_type;
|
||||
if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) return CT_INVALID; // We cannot refit to mixed cargoes in an automated way
|
||||
CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type);
|
||||
if (!HasAtMostOneBit(cargo_mask)) {
|
||||
CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(engine_type);
|
||||
if ((cargo_mask & new_engine_default_cargoes) == cargo_mask) {
|
||||
return CARGO_NO_REFIT; // engine_type is already a mixed cargo type which matches the incoming vehicle by default, no refit required
|
||||
}
|
||||
|
||||
if (cargo_type == CT_INVALID) {
|
||||
if (v->type != VEH_TRAIN) return CT_NO_REFIT; // If the vehicle does not carry anything at all, every replacement is fine.
|
||||
return INVALID_CARGO; // We cannot refit to mixed cargoes in an automated way
|
||||
}
|
||||
|
||||
if (!part_of_chain) return CT_NO_REFIT;
|
||||
if (!IsValidCargoID(cargo_type)) {
|
||||
if (v->type != VEH_TRAIN) return CARGO_NO_REFIT; // If the vehicle does not carry anything at all, every replacement is fine.
|
||||
|
||||
if (!part_of_chain) return CARGO_NO_REFIT;
|
||||
|
||||
/* the old engine didn't have cargo capacity, but the new one does
|
||||
* now we will figure out what cargo the train is carrying and refit to fit this */
|
||||
@@ -255,11 +261,11 @@ static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, bool
|
||||
if (HasBit(available_cargo_types, v->cargo_type)) return v->cargo_type;
|
||||
}
|
||||
|
||||
return CT_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one
|
||||
return CARGO_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one
|
||||
} else {
|
||||
if (!HasBit(available_cargo_types, cargo_type)) return CT_INVALID; // We can't refit the vehicle to carry the cargo we want
|
||||
if (!HasBit(available_cargo_types, cargo_type)) return INVALID_CARGO; // We can't refit the vehicle to carry the cargo we want
|
||||
|
||||
if (part_of_chain && !VerifyAutoreplaceRefitForOrders(v, engine_type)) return CT_INVALID; // Some refit orders lose their effect
|
||||
if (part_of_chain && !VerifyAutoreplaceRefitForOrders(v, engine_type)) return INVALID_CARGO; // Some refit orders lose their effect
|
||||
|
||||
return cargo_type;
|
||||
}
|
||||
@@ -324,7 +330,7 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic
|
||||
|
||||
/* Does it need to be refitted */
|
||||
CargoID refit_cargo = GetNewCargoTypeForReplace(old_veh, e, part_of_chain);
|
||||
if (refit_cargo == CT_INVALID) {
|
||||
if (!IsValidCargoID(refit_cargo)) {
|
||||
if (!IsLocalCompany()) return CommandCost();
|
||||
|
||||
SetDParam(0, old_veh->index);
|
||||
@@ -346,14 +352,14 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic
|
||||
|
||||
/* Build the new vehicle */
|
||||
VehicleID new_veh_id;
|
||||
std::tie(cost, new_veh_id, std::ignore, std::ignore, std::ignore) = Command<CMD_BUILD_VEHICLE>::Do(DC_EXEC | DC_AUTOREPLACE, old_veh->tile, e, true, CT_INVALID, INVALID_CLIENT_ID);
|
||||
std::tie(cost, new_veh_id, std::ignore, std::ignore, std::ignore) = Command<CMD_BUILD_VEHICLE>::Do(DC_EXEC | DC_AUTOREPLACE, old_veh->tile, e, true, INVALID_CARGO, INVALID_CLIENT_ID);
|
||||
if (cost.Failed()) return cost;
|
||||
|
||||
Vehicle *new_veh = Vehicle::Get(new_veh_id);
|
||||
*new_vehicle = new_veh;
|
||||
|
||||
/* Refit the vehicle if needed */
|
||||
if (refit_cargo != CT_NO_REFIT) {
|
||||
if (refit_cargo != CARGO_NO_REFIT) {
|
||||
byte subtype = GetBestFittingSubType(old_veh, new_veh, refit_cargo);
|
||||
|
||||
cost.AddCost(std::get<0>(Command<CMD_REFIT_VEHICLE>::Do(DC_EXEC, new_veh->index, refit_cargo, subtype, false, false, 0)));
|
||||
@@ -406,7 +412,7 @@ static CommandCost CopyHeadSpecificThings(Vehicle *old_head, Vehicle *new_head,
|
||||
if (cost.Succeeded() && old_head != new_head) cost.AddCost(Command<CMD_CLONE_ORDER>::Do(DC_EXEC, CO_SHARE, new_head->index, old_head->index));
|
||||
|
||||
/* Copy group membership */
|
||||
if (cost.Succeeded() && old_head != new_head) cost.AddCost(std::get<0>(Command<CMD_ADD_VEHICLE_GROUP>::Do(DC_EXEC, old_head->group_id, new_head->index, false)));
|
||||
if (cost.Succeeded() && old_head != new_head) cost.AddCost(std::get<0>(Command<CMD_ADD_VEHICLE_GROUP>::Do(DC_EXEC, old_head->group_id, new_head->index, false, VehicleListIdentifier{})));
|
||||
|
||||
/* Perform start/stop check whether the new vehicle suits newgrf restrictions etc. */
|
||||
if (cost.Succeeded()) {
|
||||
@@ -445,7 +451,7 @@ static CommandCost ReplaceFreeUnit(Vehicle **single_unit, DoCommandFlag flags, b
|
||||
Train *old_v = Train::From(*single_unit);
|
||||
assert(!old_v->IsArticulatedPart() && !old_v->IsRearDualheaded());
|
||||
|
||||
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0);
|
||||
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, (Money)0);
|
||||
|
||||
/* Build and refit replacement vehicle */
|
||||
Vehicle *new_v = nullptr;
|
||||
@@ -484,6 +490,21 @@ static CommandCost ReplaceFreeUnit(Vehicle **single_unit, DoCommandFlag flags, b
|
||||
return cost;
|
||||
}
|
||||
|
||||
/** Struct for recording vehicle chain replacement information. */
|
||||
struct ReplaceChainItem {
|
||||
Vehicle *old_veh; ///< Old vehicle to replace.
|
||||
Vehicle *new_veh; ///< Replacement vehicle, or nullptr if no replacement.
|
||||
Money cost; /// Cost of buying and refitting replacement.
|
||||
|
||||
ReplaceChainItem(Vehicle *old_veh, Vehicle *new_veh, Money cost) : old_veh(old_veh), new_veh(new_veh), cost(cost) { }
|
||||
|
||||
/**
|
||||
* Get vehicle to use for this position.
|
||||
* @return Either the new vehicle, or the old vehicle if there is no replacement.
|
||||
*/
|
||||
Vehicle *GetVehicle() const { return new_veh == nullptr ? old_veh : new_veh; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace a whole vehicle chain
|
||||
* @param chain vehicle chain to let autoreplace/renew operator on
|
||||
@@ -497,35 +518,27 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
Vehicle *old_head = *chain;
|
||||
assert(old_head->IsPrimaryVehicle());
|
||||
|
||||
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0);
|
||||
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, (Money)0);
|
||||
|
||||
if (old_head->type == VEH_TRAIN) {
|
||||
/* Store the length of the old vehicle chain, rounded up to whole tiles */
|
||||
uint16 old_total_length = CeilDiv(Train::From(old_head)->gcache.cached_total_length, TILE_SIZE) * TILE_SIZE;
|
||||
uint16_t old_total_length = CeilDiv(Train::From(old_head)->gcache.cached_total_length, TILE_SIZE) * TILE_SIZE;
|
||||
|
||||
int num_units = 0; ///< Number of units in the chain
|
||||
for (Train *w = Train::From(old_head); w != nullptr; w = w->GetNextUnit()) num_units++;
|
||||
|
||||
Train **old_vehs = CallocT<Train *>(num_units); ///< Will store vehicles of the old chain in their order
|
||||
Train **new_vehs = CallocT<Train *>(num_units); ///< New vehicles corresponding to old_vehs or nullptr if no replacement
|
||||
Money *new_costs = MallocT<Money>(num_units); ///< Costs for buying and refitting the new vehicles
|
||||
std::vector<ReplaceChainItem> replacements;
|
||||
|
||||
/* Collect vehicles and build replacements
|
||||
* Note: The replacement vehicles can only successfully build as long as the old vehicles are still in their chain */
|
||||
int i;
|
||||
Train *w;
|
||||
for (w = Train::From(old_head), i = 0; w != nullptr; w = w->GetNextUnit(), i++) {
|
||||
assert(i < num_units);
|
||||
old_vehs[i] = w;
|
||||
for (Train *w = Train::From(old_head); w != nullptr; w = w->GetNextUnit()) {
|
||||
ReplaceChainItem &replacement = replacements.emplace_back(w, nullptr, 0);
|
||||
|
||||
CommandCost ret = BuildReplacementVehicle(old_vehs[i], (Vehicle**)&new_vehs[i], true);
|
||||
CommandCost ret = BuildReplacementVehicle(replacement.old_veh, &replacement.new_veh, true);
|
||||
cost.AddCost(ret);
|
||||
if (cost.Failed()) break;
|
||||
|
||||
new_costs[i] = ret.GetCost();
|
||||
if (new_vehs[i] != nullptr) *nothing_to_do = false;
|
||||
replacement.cost = ret.GetCost();
|
||||
if (replacement.new_veh != nullptr) *nothing_to_do = false;
|
||||
}
|
||||
Train *new_head = (new_vehs[0] != nullptr ? new_vehs[0] : old_vehs[0]);
|
||||
Vehicle *new_head = replacements.front().GetVehicle();
|
||||
|
||||
/* Note: When autoreplace has already failed here, old_vehs[] is not completely initialized. But it is also not needed. */
|
||||
if (cost.Succeeded()) {
|
||||
@@ -539,18 +552,18 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
* We do this from back to front, so that the head of the temporary vehicle chain does not change all the time.
|
||||
* That way we also have less trouble when exceeding the unitnumber limit.
|
||||
* OTOH the vehicle attach callback is more expensive this way :s */
|
||||
Train *last_engine = nullptr; ///< Shall store the last engine unit after this step
|
||||
Vehicle *last_engine = nullptr; ///< Shall store the last engine unit after this step
|
||||
if (cost.Succeeded()) {
|
||||
for (int i = num_units - 1; i > 0; i--) {
|
||||
Train *append = (new_vehs[i] != nullptr ? new_vehs[i] : old_vehs[i]);
|
||||
for (auto it = std::rbegin(replacements); it != std::rend(replacements); ++it) {
|
||||
Vehicle *append = it->GetVehicle();
|
||||
|
||||
if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) continue;
|
||||
|
||||
if (new_vehs[i] != nullptr) {
|
||||
if (it->new_veh != nullptr) {
|
||||
/* Move the old engine to a separate row with DC_AUTOREPLACE. Else
|
||||
* moving the wagon in front may fail later due to unitnumber limit.
|
||||
* (We have to attach wagons without DC_AUTOREPLACE.) */
|
||||
CmdMoveVehicle(old_vehs[i], nullptr, DC_EXEC | DC_AUTOREPLACE, false);
|
||||
CmdMoveVehicle(it->old_veh, nullptr, DC_EXEC | DC_AUTOREPLACE, false);
|
||||
}
|
||||
|
||||
if (last_engine == nullptr) last_engine = append;
|
||||
@@ -561,15 +574,15 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
}
|
||||
|
||||
/* When wagon removal is enabled and the new engines without any wagons are already longer than the old, we have to fail */
|
||||
if (cost.Succeeded() && wagon_removal && new_head->gcache.cached_total_length > old_total_length) cost = CommandCost(STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT);
|
||||
if (cost.Succeeded() && wagon_removal && Train::From(new_head)->gcache.cached_total_length > old_total_length) cost = CommandCost(STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT);
|
||||
|
||||
/* Append/insert wagons into the new vehicle chain
|
||||
* We do this from back to front, so we can stop when wagon removal or maximum train length (i.e. from mammoth-train setting) is triggered.
|
||||
*/
|
||||
if (cost.Succeeded()) {
|
||||
for (int i = num_units - 1; i > 0; i--) {
|
||||
for (auto it = std::rbegin(replacements); it != std::rend(replacements); ++it) {
|
||||
assert(last_engine != nullptr);
|
||||
Vehicle *append = (new_vehs[i] != nullptr ? new_vehs[i] : old_vehs[i]);
|
||||
Vehicle *append = it->GetVehicle();
|
||||
|
||||
if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) {
|
||||
/* Insert wagon after 'last_engine' */
|
||||
@@ -578,7 +591,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
/* When we allow removal of wagons, either the move failing due
|
||||
* to the train becoming too long, or the train becoming longer
|
||||
* would move the vehicle to the empty vehicle chain. */
|
||||
if (wagon_removal && (res.Failed() ? res.GetErrorMessage() == STR_ERROR_TRAIN_TOO_LONG : new_head->gcache.cached_total_length > old_total_length)) {
|
||||
if (wagon_removal && (res.Failed() ? res.GetErrorMessage() == STR_ERROR_TRAIN_TOO_LONG : Train::From(new_head)->gcache.cached_total_length > old_total_length)) {
|
||||
CmdMoveVehicle(append, nullptr, DC_EXEC | DC_AUTOREPLACE, false);
|
||||
break;
|
||||
}
|
||||
@@ -588,16 +601,16 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
} else {
|
||||
/* We have reached 'last_engine', continue with the next engine towards the front */
|
||||
assert(append == last_engine);
|
||||
last_engine = last_engine->GetPrevUnit();
|
||||
last_engine = Train::From(last_engine)->GetPrevUnit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sell superfluous new vehicles that could not be inserted. */
|
||||
if (cost.Succeeded() && wagon_removal) {
|
||||
assert(new_head->gcache.cached_total_length <= _settings_game.vehicle.max_train_length * TILE_SIZE);
|
||||
for (int i = 1; i < num_units; i++) {
|
||||
Vehicle *wagon = new_vehs[i];
|
||||
assert(Train::From(new_head)->gcache.cached_total_length <= _settings_game.vehicle.max_train_length * TILE_SIZE);
|
||||
for (auto it = std::next(std::begin(replacements)); it != std::end(replacements); ++it) {
|
||||
Vehicle *wagon = it->new_veh;
|
||||
if (wagon == nullptr) continue;
|
||||
if (wagon->First() == new_head) break;
|
||||
|
||||
@@ -606,11 +619,11 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
/* Sell wagon */
|
||||
[[maybe_unused]] CommandCost ret = Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, wagon->index, false, false, INVALID_CLIENT_ID);
|
||||
assert(ret.Succeeded());
|
||||
new_vehs[i] = nullptr;
|
||||
it->new_veh = nullptr;
|
||||
|
||||
/* Revert the money subtraction when the vehicle was built.
|
||||
* This value is different from the sell value, esp. because of refitting */
|
||||
cost.AddCost(-new_costs[i]);
|
||||
cost.AddCost(-it->cost);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,8 +638,8 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
}
|
||||
|
||||
/* Transfer cargo of old vehicles and sell them */
|
||||
for (int i = 0; i < num_units; i++) {
|
||||
Vehicle *w = old_vehs[i];
|
||||
for (auto it = std::begin(replacements); it != std::end(replacements); ++it) {
|
||||
Vehicle *w = it->old_veh;
|
||||
/* Is the vehicle again part of the new chain?
|
||||
* Note: We cannot test 'new_vehs[i] != nullptr' as wagon removal might cause to remove both */
|
||||
if (w->First() == new_head) continue;
|
||||
@@ -638,8 +651,8 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
* it from failing due to engine limits. */
|
||||
cost.AddCost(Command<CMD_SELL_VEHICLE>::Do(flags | DC_AUTOREPLACE, w->index, false, false, INVALID_CLIENT_ID));
|
||||
if ((flags & DC_EXEC) != 0) {
|
||||
old_vehs[i] = nullptr;
|
||||
if (i == 0) old_head = nullptr;
|
||||
it->old_veh = nullptr;
|
||||
if (it == std::begin(replacements)) old_head = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,8 +669,8 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
|
||||
assert(Train::From(old_head)->GetNextUnit() == nullptr);
|
||||
|
||||
for (int i = num_units - 1; i > 0; i--) {
|
||||
[[maybe_unused]] CommandCost ret = CmdMoveVehicle(old_vehs[i], old_head, DC_EXEC | DC_AUTOREPLACE, false);
|
||||
for (auto it = std::rbegin(replacements); it != std::rend(replacements); ++it) {
|
||||
[[maybe_unused]] CommandCost ret = CmdMoveVehicle(it->old_veh, old_head, DC_EXEC | DC_AUTOREPLACE, false);
|
||||
assert(ret.Succeeded());
|
||||
}
|
||||
}
|
||||
@@ -665,17 +678,13 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
|
||||
/* Finally undo buying of new vehicles */
|
||||
if ((flags & DC_EXEC) == 0) {
|
||||
for (int i = num_units - 1; i >= 0; i--) {
|
||||
if (new_vehs[i] != nullptr) {
|
||||
Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, new_vehs[i]->index, false, false, INVALID_CLIENT_ID);
|
||||
new_vehs[i] = nullptr;
|
||||
for (auto it = std::rbegin(replacements); it != std::rend(replacements); ++it) {
|
||||
if (it->new_veh != nullptr) {
|
||||
Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, it->new_veh->index, false, false, INVALID_CLIENT_ID);
|
||||
it->new_veh = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(old_vehs);
|
||||
free(new_vehs);
|
||||
free(new_costs);
|
||||
} else {
|
||||
/* Build and refit replacement vehicle */
|
||||
Vehicle *new_head = nullptr;
|
||||
@@ -756,7 +765,7 @@ CommandCost CmdAutoreplaceVehicle(DoCommandFlag flags, VehicleID veh_id)
|
||||
w = (!free_wagon && w->type == VEH_TRAIN ? Train::From(w)->GetNextUnit() : nullptr);
|
||||
}
|
||||
|
||||
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0);
|
||||
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, (Money)0);
|
||||
bool nothing_to_do = true;
|
||||
|
||||
if (any_replacements) {
|
||||
@@ -781,7 +790,6 @@ CommandCost CmdAutoreplaceVehicle(DoCommandFlag flags, VehicleID veh_id)
|
||||
RestoreRandomSeeds(saved_seeds);
|
||||
|
||||
if (cost.Succeeded() && (flags & DC_EXEC) != 0) {
|
||||
CommandCost ret;
|
||||
if (free_wagon) {
|
||||
ret = ReplaceFreeUnit(&v, flags, ¬hing_to_do);
|
||||
} else {
|
||||
|
||||
@@ -22,7 +22,7 @@ CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, Group
|
||||
* Remove all engine replacement settings for the given company.
|
||||
* @param c the company.
|
||||
*/
|
||||
static inline void RemoveAllEngineReplacementForCompany(Company *c)
|
||||
inline void RemoveAllEngineReplacementForCompany(Company *c)
|
||||
{
|
||||
RemoveAllEngineReplacement(&c->engine_renew_list);
|
||||
}
|
||||
@@ -36,7 +36,7 @@ static inline void RemoveAllEngineReplacementForCompany(Company *c)
|
||||
* @return The engine type to replace with, or INVALID_ENGINE if no
|
||||
* replacement is in the list.
|
||||
*/
|
||||
static inline EngineID EngineReplacementForCompany(const Company *c, EngineID engine, GroupID group, bool *replace_when_old = nullptr)
|
||||
inline EngineID EngineReplacementForCompany(const Company *c, EngineID engine, GroupID group, bool *replace_when_old = nullptr)
|
||||
{
|
||||
return EngineReplacement(c->engine_renew_list, engine, group, replace_when_old);
|
||||
}
|
||||
@@ -48,7 +48,7 @@ static inline EngineID EngineReplacementForCompany(const Company *c, EngineID en
|
||||
* @param group The group related to this replacement.
|
||||
* @return true if a replacement was set up, false otherwise.
|
||||
*/
|
||||
static inline bool EngineHasReplacementForCompany(const Company *c, EngineID engine, GroupID group)
|
||||
inline bool EngineHasReplacementForCompany(const Company *c, EngineID engine, GroupID group)
|
||||
{
|
||||
return EngineReplacementForCompany(c, engine, group) != INVALID_ENGINE;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ static inline bool EngineHasReplacementForCompany(const Company *c, EngineID eng
|
||||
* @param group The group related to this replacement.
|
||||
* @return True if a replacement when old was set up, false otherwise.
|
||||
*/
|
||||
static inline bool EngineHasReplacementWhenOldForCompany(const Company *c, EngineID engine, GroupID group)
|
||||
inline bool EngineHasReplacementWhenOldForCompany(const Company *c, EngineID engine, GroupID group)
|
||||
{
|
||||
bool replace_when_old;
|
||||
EngineReplacement(c->engine_renew_list, engine, group, &replace_when_old);
|
||||
@@ -77,7 +77,7 @@ static inline bool EngineHasReplacementWhenOldForCompany(const Company *c, Engin
|
||||
* @param flags The calling command flags.
|
||||
* @return 0 on success, CMD_ERROR on failure.
|
||||
*/
|
||||
static inline CommandCost AddEngineReplacementForCompany(Company *c, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags)
|
||||
inline CommandCost AddEngineReplacementForCompany(Company *c, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags)
|
||||
{
|
||||
return AddEngineReplacement(&c->engine_renew_list, old_engine, new_engine, group, replace_when_old, flags);
|
||||
}
|
||||
@@ -90,7 +90,7 @@ static inline CommandCost AddEngineReplacementForCompany(Company *c, EngineID ol
|
||||
* @param flags The calling command flags.
|
||||
* @return 0 on success, CMD_ERROR on failure.
|
||||
*/
|
||||
static inline CommandCost RemoveEngineReplacementForCompany(Company *c, EngineID engine, GroupID group, DoCommandFlag flags)
|
||||
inline CommandCost RemoveEngineReplacementForCompany(Company *c, EngineID engine, GroupID group, DoCommandFlag flags)
|
||||
{
|
||||
return RemoveEngineReplacement(&c->engine_renew_list, engine, group, flags);
|
||||
}
|
||||
|
||||
+100
-117
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group);
|
||||
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, uint16_t min, uint16_t max, EngineID selected_id, bool show_count, GroupID selected_group);
|
||||
|
||||
static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
|
||||
{
|
||||
@@ -148,7 +148,7 @@ class ReplaceVehicleWindow : public Window {
|
||||
GUIEngineList list;
|
||||
|
||||
for (const Engine *e : Engine::IterateType(type)) {
|
||||
if (!draw_left && !this->show_hidden_engines && e->IsHidden(_local_company)) continue;
|
||||
if (!draw_left && !this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
|
||||
EngineID eid = e->index;
|
||||
switch (type) {
|
||||
case VEH_TRAIN:
|
||||
@@ -175,11 +175,15 @@ class ReplaceVehicleWindow : public Window {
|
||||
if (!CheckAutoreplaceValidity(this->sel_engine[0], eid, _local_company)) continue;
|
||||
}
|
||||
|
||||
EngineDisplayFlags flags = (side == 0) ? EngineDisplayFlags::None : e->display_flags;
|
||||
if (side == 1 && eid == this->sel_engine[0]) flags |= EngineDisplayFlags::Shaded;
|
||||
list.emplace_back(eid, e->info.variant_id, flags, 0);
|
||||
list.emplace_back(eid, e->info.variant_id, (side == 0) ? EngineDisplayFlags::None : e->display_flags, 0);
|
||||
|
||||
if (side == 1 && e->info.variant_id != INVALID_ENGINE) variants.push_back(e->info.variant_id);
|
||||
if (side == 1) {
|
||||
EngineID parent = e->info.variant_id;
|
||||
while (parent != INVALID_ENGINE) {
|
||||
variants.push_back(parent);
|
||||
parent = Engine::Get(parent)->info.variant_id;
|
||||
}
|
||||
}
|
||||
if (eid == this->sel_engine[side]) selected_engine = eid; // The selected engine is still in the list
|
||||
}
|
||||
|
||||
@@ -195,10 +199,10 @@ class ReplaceVehicleWindow : public Window {
|
||||
|
||||
this->sel_engine[side] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore)
|
||||
if (draw_left) {
|
||||
EngList_Sort(&list, &EngineNumberSorter);
|
||||
EngList_Sort(list, &EngineNumberSorter);
|
||||
} else {
|
||||
_engine_sort_direction = this->descending_sort_order;
|
||||
EngList_Sort(&list, _engine_sort_functions[this->window_number][this->sort_criteria]);
|
||||
EngList_Sort(list, _engine_sort_functions[this->window_number][this->sort_criteria]);
|
||||
}
|
||||
|
||||
this->engines[side].clear();
|
||||
@@ -217,8 +221,8 @@ class ReplaceVehicleWindow : public Window {
|
||||
if (this->engines[0].NeedRebuild()) {
|
||||
/* We need to rebuild the left engines list */
|
||||
this->GenerateReplaceVehList(true);
|
||||
this->vscroll[0]->SetCount((uint)this->engines[0].size());
|
||||
if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && this->engines[0].size() != 0) {
|
||||
this->vscroll[0]->SetCount(this->engines[0].size());
|
||||
if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && !this->engines[0].empty()) {
|
||||
this->sel_engine[0] = this->engines[0][0].engine_id;
|
||||
}
|
||||
}
|
||||
@@ -229,6 +233,7 @@ class ReplaceVehicleWindow : public Window {
|
||||
/* Always empty the right engines list when nothing is selected in the left engines list */
|
||||
this->engines[1].clear();
|
||||
this->sel_engine[1] = INVALID_ENGINE;
|
||||
this->vscroll[1]->SetCount(this->engines[1].size());
|
||||
} else {
|
||||
if (this->reset_sel_engine && this->sel_engine[0] != INVALID_ENGINE) {
|
||||
/* Select the current replacement for sel_engine[0]. */
|
||||
@@ -237,7 +242,7 @@ class ReplaceVehicleWindow : public Window {
|
||||
}
|
||||
/* Regenerate the list on the right. Note: This resets sel_engine[1] to INVALID_ENGINE, if it is no longer available. */
|
||||
this->GenerateReplaceVehList(false);
|
||||
this->vscroll[1]->SetCount((uint)this->engines[1].size());
|
||||
this->vscroll[1]->SetCount(this->engines[1].size());
|
||||
if (this->reset_sel_engine && this->sel_engine[1] != INVALID_ENGINE) {
|
||||
int position = 0;
|
||||
for (const auto &item : this->engines[1]) {
|
||||
@@ -265,6 +270,21 @@ class ReplaceVehicleWindow : public Window {
|
||||
Command<CMD_SET_AUTOREPLACE>::Post(this->sel_group, veh_from, veh_to, replace_when_old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform tasks after rail or road type is changed.
|
||||
*/
|
||||
void OnRailRoadTypeChange()
|
||||
{
|
||||
/* Reset scrollbar positions */
|
||||
this->vscroll[0]->SetPosition(0);
|
||||
this->vscroll[1]->SetPosition(0);
|
||||
/* Rebuild the lists */
|
||||
this->engines[0].ForceRebuild();
|
||||
this->engines[1].ForceRebuild();
|
||||
this->reset_sel_engine = true;
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
public:
|
||||
ReplaceVehicleWindow(WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc)
|
||||
{
|
||||
@@ -289,18 +309,13 @@ public:
|
||||
widget->SetLowered(this->show_hidden_engines);
|
||||
this->FinishInitNested(vehicletype);
|
||||
|
||||
if (vehicletype == VEH_TRAIN || vehicletype == VEH_ROAD) {
|
||||
widget = this->GetWidget<NWidgetCore>(WID_RV_RAIL_ROAD_TYPE_DROPDOWN);
|
||||
widget->tool_tip = STR_REPLACE_HELP_RAILTYPE + vehicletype;
|
||||
}
|
||||
|
||||
this->sort_criteria = _engine_sort_last_criteria[vehicletype];
|
||||
this->descending_sort_order = _engine_sort_last_order[vehicletype];
|
||||
this->owner = _local_company;
|
||||
this->sel_group = id_g;
|
||||
}
|
||||
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_SORT_ASCENDING_DESCENDING: {
|
||||
@@ -319,7 +334,7 @@ public:
|
||||
|
||||
case WID_RV_LEFT_DETAILS:
|
||||
case WID_RV_RIGHT_DETAILS:
|
||||
size->height = FONT_HEIGHT_NORMAL * this->details_height + padding.height;
|
||||
size->height = GetCharacterHeight(FS_NORMAL) * this->details_height + padding.height;
|
||||
break;
|
||||
|
||||
case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: {
|
||||
@@ -352,28 +367,21 @@ public:
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_RV_RAIL_ROAD_TYPE_DROPDOWN: {
|
||||
case WID_RV_RAIL_TYPE_DROPDOWN: {
|
||||
Dimension d = {0, 0};
|
||||
switch (this->window_number) {
|
||||
case VEH_TRAIN:
|
||||
for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(rt);
|
||||
/* Skip rail type if it has no label */
|
||||
if (rti->label == 0) continue;
|
||||
d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text));
|
||||
}
|
||||
break;
|
||||
for (const RailType &rt : _sorted_railtypes) {
|
||||
d = maxdim(d, GetStringBoundingBox(GetRailTypeInfo(rt)->strings.replace_text));
|
||||
}
|
||||
d.width += padding.width;
|
||||
d.height += padding.height;
|
||||
*size = maxdim(*size, d);
|
||||
break;
|
||||
}
|
||||
|
||||
case VEH_ROAD:
|
||||
for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
|
||||
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
|
||||
/* Skip road type if it has no label */
|
||||
if (rti->label == 0) continue;
|
||||
d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text));
|
||||
}
|
||||
break;
|
||||
|
||||
default: NOT_REACHED();
|
||||
case WID_RV_ROAD_TYPE_DROPDOWN: {
|
||||
Dimension d = {0, 0};
|
||||
for (const RoadType &rt : _sorted_roadtypes) {
|
||||
d = maxdim(d, GetStringBoundingBox(GetRoadTypeInfo(rt)->strings.replace_text));
|
||||
}
|
||||
d.width += padding.width;
|
||||
d.height += padding.height;
|
||||
@@ -394,7 +402,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SetStringParameters(int widget) const override
|
||||
void SetStringParameters(WidgetID widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_CAPTION:
|
||||
@@ -438,10 +446,18 @@ public:
|
||||
case WID_RV_TRAIN_ENGINEWAGON_DROPDOWN:
|
||||
SetDParam(0, this->replace_engines ? STR_REPLACE_ENGINES : STR_REPLACE_WAGONS);
|
||||
break;
|
||||
|
||||
case WID_RV_RAIL_TYPE_DROPDOWN:
|
||||
SetDParam(0, this->sel_railtype == INVALID_RAILTYPE ? STR_REPLACE_ALL_RAILTYPE : GetRailTypeInfo(this->sel_railtype)->strings.replace_text);
|
||||
break;
|
||||
|
||||
case WID_RV_ROAD_TYPE_DROPDOWN:
|
||||
SetDParam(0, this->sel_roadtype == INVALID_ROADTYPE ? STR_REPLACE_ALL_ROADTYPE : GetRoadTypeInfo(this->sel_roadtype)->strings.replace_text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_SORT_ASCENDING_DESCENDING:
|
||||
@@ -498,20 +514,6 @@ public:
|
||||
* or The selected vehicle has no replacement set up */
|
||||
this->SetWidgetDisabledState(WID_RV_STOP_REPLACE, this->sel_engine[0] == INVALID_ENGINE || !EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group));
|
||||
|
||||
switch (this->window_number) {
|
||||
case VEH_TRAIN:
|
||||
/* Show the selected railtype in the pulldown menu */
|
||||
this->GetWidget<NWidgetCore>(WID_RV_RAIL_ROAD_TYPE_DROPDOWN)->widget_data = sel_railtype == INVALID_RAILTYPE ? STR_REPLACE_ALL_RAILTYPE : GetRailTypeInfo(sel_railtype)->strings.replace_text;
|
||||
break;
|
||||
|
||||
case VEH_ROAD:
|
||||
/* Show the selected roadtype in the pulldown menu */
|
||||
this->GetWidget<NWidgetCore>(WID_RV_RAIL_ROAD_TYPE_DROPDOWN)->widget_data = sel_roadtype == INVALID_ROADTYPE ? STR_REPLACE_ALL_ROADTYPE : GetRoadTypeInfo(sel_roadtype)->strings.replace_text;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
this->DrawWidgets();
|
||||
|
||||
if (!this->IsShaded()) {
|
||||
@@ -528,7 +530,7 @@ public:
|
||||
const Rect r = this->GetWidget<NWidgetBase>(side == 0 ? WID_RV_LEFT_DETAILS : WID_RV_RIGHT_DETAILS)->GetCurrentRect()
|
||||
.Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect);
|
||||
int text_end = DrawVehiclePurchaseInfo(r.left, r.right, r.top, this->sel_engine[side], ted);
|
||||
needed_height = std::max(needed_height, (text_end - r.top) / FONT_HEIGHT_NORMAL);
|
||||
needed_height = std::max(needed_height, (text_end - r.top) / GetCharacterHeight(FS_NORMAL));
|
||||
}
|
||||
}
|
||||
if (needed_height != this->details_height) { // Details window are not high enough, enlarge them.
|
||||
@@ -539,7 +541,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_SORT_ASCENDING_DESCENDING:
|
||||
@@ -563,22 +565,18 @@ public:
|
||||
|
||||
case WID_RV_TRAIN_ENGINEWAGON_DROPDOWN: {
|
||||
DropDownList list;
|
||||
list.emplace_back(new DropDownListStringItem(STR_REPLACE_ENGINES, 1, false));
|
||||
list.emplace_back(new DropDownListStringItem(STR_REPLACE_WAGONS, 0, false));
|
||||
list.push_back(std::make_unique<DropDownListStringItem>(STR_REPLACE_ENGINES, 1, false));
|
||||
list.push_back(std::make_unique<DropDownListStringItem>(STR_REPLACE_WAGONS, 0, false));
|
||||
ShowDropDownList(this, std::move(list), this->replace_engines ? 1 : 0, WID_RV_TRAIN_ENGINEWAGON_DROPDOWN);
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_RV_RAIL_ROAD_TYPE_DROPDOWN: // Rail/roadtype selection dropdown menu
|
||||
switch (this->window_number) {
|
||||
case VEH_TRAIN:
|
||||
ShowDropDownList(this, GetRailTypeDropDownList(true, true), sel_railtype, WID_RV_RAIL_ROAD_TYPE_DROPDOWN);
|
||||
break;
|
||||
case WID_RV_RAIL_TYPE_DROPDOWN: // Railtype selection dropdown menu
|
||||
ShowDropDownList(this, GetRailTypeDropDownList(true, true), this->sel_railtype, widget);
|
||||
break;
|
||||
|
||||
case VEH_ROAD:
|
||||
ShowDropDownList(this, GetRoadTypeDropDownList(RTTB_ROAD | RTTB_TRAM, true, true), sel_roadtype, WID_RV_RAIL_ROAD_TYPE_DROPDOWN);
|
||||
break;
|
||||
}
|
||||
case WID_RV_ROAD_TYPE_DROPDOWN: // Roadtype selection dropdown menu
|
||||
ShowDropDownList(this, GetRoadTypeDropDownList(RTTB_ROAD | RTTB_TRAM, true, true), this->sel_roadtype, widget);
|
||||
break;
|
||||
|
||||
case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: {
|
||||
@@ -617,12 +615,11 @@ public:
|
||||
} else {
|
||||
click_side = 1;
|
||||
}
|
||||
uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget);
|
||||
size_t engine_count = this->engines[click_side].size();
|
||||
|
||||
EngineID e = INVALID_ENGINE;
|
||||
if (i < engine_count) {
|
||||
const auto &item = this->engines[click_side][i];
|
||||
const auto it = this->vscroll[click_side]->GetScrolledItemFromWidget(this->engines[click_side], pt.y, this, widget);
|
||||
if (it != this->engines[click_side].end()) {
|
||||
const auto &item = *it;
|
||||
const Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL);
|
||||
if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) {
|
||||
/* toggle folded flag on engine */
|
||||
@@ -658,7 +655,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
void OnDropdownSelect(WidgetID widget, int index) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_SORT_DROPDOWN:
|
||||
@@ -670,34 +667,21 @@ public:
|
||||
}
|
||||
break;
|
||||
|
||||
case WID_RV_RAIL_ROAD_TYPE_DROPDOWN:
|
||||
switch (this->window_number) {
|
||||
case VEH_TRAIN: {
|
||||
RailType temp = (RailType)index;
|
||||
if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything
|
||||
sel_railtype = temp;
|
||||
break;
|
||||
}
|
||||
|
||||
case VEH_ROAD: {
|
||||
RoadType temp = (RoadType)index;
|
||||
if (temp == sel_roadtype) return; // we didn't select a new one. No need to change anything
|
||||
sel_roadtype = temp;
|
||||
break;
|
||||
}
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
/* Reset scrollbar positions */
|
||||
this->vscroll[0]->SetPosition(0);
|
||||
this->vscroll[1]->SetPosition(0);
|
||||
/* Rebuild the lists */
|
||||
this->engines[0].ForceRebuild();
|
||||
this->engines[1].ForceRebuild();
|
||||
this->reset_sel_engine = true;
|
||||
this->SetDirty();
|
||||
case WID_RV_RAIL_TYPE_DROPDOWN: {
|
||||
RailType temp = (RailType)index;
|
||||
if (temp == this->sel_railtype) return; // we didn't select a new one. No need to change anything
|
||||
this->sel_railtype = temp;
|
||||
this->OnRailRoadTypeChange();
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_RV_ROAD_TYPE_DROPDOWN: {
|
||||
RoadType temp = (RoadType)index;
|
||||
if (temp == this->sel_roadtype) return; // we didn't select a new one. No need to change anything
|
||||
this->sel_roadtype = temp;
|
||||
this->OnRailRoadTypeChange();
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_RV_TRAIN_ENGINEWAGON_DROPDOWN: {
|
||||
this->replace_engines = index != 0;
|
||||
@@ -713,16 +697,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool OnTooltip(Point pt, int widget, TooltipCloseCondition close_cond) override
|
||||
bool OnTooltip([[maybe_unused]] Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
|
||||
{
|
||||
if (widget != WID_RV_TRAIN_WAGONREMOVE_TOGGLE) return false;
|
||||
|
||||
if (Group::IsValidID(this->sel_group)) {
|
||||
uint64 params[1];
|
||||
params[0] = STR_REPLACE_REMOVE_WAGON_HELP;
|
||||
GuiShowTooltips(this, STR_REPLACE_REMOVE_WAGON_GROUP_HELP, 1, params, close_cond);
|
||||
SetDParam(0, STR_REPLACE_REMOVE_WAGON_HELP);
|
||||
GuiShowTooltips(this, STR_REPLACE_REMOVE_WAGON_GROUP_HELP, close_cond, 1);
|
||||
} else {
|
||||
GuiShowTooltips(this, STR_REPLACE_REMOVE_WAGON_HELP, 0, nullptr, close_cond);
|
||||
GuiShowTooltips(this, STR_REPLACE_REMOVE_WAGON_HELP, close_cond);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -738,7 +721,7 @@ public:
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
|
||||
{
|
||||
if (data != 0) {
|
||||
/* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
|
||||
@@ -749,7 +732,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = {
|
||||
static constexpr NWidgetPart _nested_replace_rail_vehicle_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
@@ -768,8 +751,8 @@ static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_RAIL_ROAD_TYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetFill(1, 0), SetResize(1, 0),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_ENGINEWAGON_DROPDOWN), SetDataTip(STR_BLACK_STRING, STR_REPLACE_ENGINE_WAGON_SELECT_HELP),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_RAIL_TYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(STR_JUST_STRING, STR_REPLACE_HELP_RAILTYPE), SetFill(1, 0), SetResize(1, 0),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_ENGINEWAGON_DROPDOWN), SetDataTip(STR_JUST_STRING, STR_REPLACE_ENGINE_WAGON_SELECT_HELP),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), EndContainer(),
|
||||
EndContainer(),
|
||||
@@ -806,14 +789,14 @@ static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = {
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _replace_rail_vehicle_desc(
|
||||
static WindowDesc _replace_rail_vehicle_desc(__FILE__, __LINE__,
|
||||
WDP_AUTO, "replace_vehicle_train", 500, 140,
|
||||
WC_REPLACE_VEHICLE, WC_NONE,
|
||||
WDF_CONSTRUCTION,
|
||||
_nested_replace_rail_vehicle_widgets, lengthof(_nested_replace_rail_vehicle_widgets)
|
||||
std::begin(_nested_replace_rail_vehicle_widgets), std::end(_nested_replace_rail_vehicle_widgets)
|
||||
);
|
||||
|
||||
static const NWidgetPart _nested_replace_road_vehicle_widgets[] = {
|
||||
static constexpr NWidgetPart _nested_replace_road_vehicle_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
@@ -831,7 +814,7 @@ static const NWidgetPart _nested_replace_road_vehicle_widgets[] = {
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_RAIL_ROAD_TYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetFill(1, 0), SetResize(1, 0),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_ROAD_TYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(STR_JUST_STRING, STR_REPLACE_HELP_ROADTYPE), SetFill(1, 0), SetResize(1, 0),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL),
|
||||
@@ -864,14 +847,14 @@ static const NWidgetPart _nested_replace_road_vehicle_widgets[] = {
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _replace_road_vehicle_desc(
|
||||
static WindowDesc _replace_road_vehicle_desc(__FILE__, __LINE__,
|
||||
WDP_AUTO, "replace_vehicle_road", 500, 140,
|
||||
WC_REPLACE_VEHICLE, WC_NONE,
|
||||
WDF_CONSTRUCTION,
|
||||
_nested_replace_road_vehicle_widgets, lengthof(_nested_replace_road_vehicle_widgets)
|
||||
std::begin(_nested_replace_road_vehicle_widgets), std::end(_nested_replace_road_vehicle_widgets)
|
||||
);
|
||||
|
||||
static const NWidgetPart _nested_replace_vehicle_widgets[] = {
|
||||
static constexpr NWidgetPart _nested_replace_vehicle_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetMinimalSize(433, 14), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
@@ -918,11 +901,11 @@ static const NWidgetPart _nested_replace_vehicle_widgets[] = {
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _replace_vehicle_desc(
|
||||
static WindowDesc _replace_vehicle_desc(__FILE__, __LINE__,
|
||||
WDP_AUTO, "replace_vehicle", 456, 118,
|
||||
WC_REPLACE_VEHICLE, WC_NONE,
|
||||
WDF_CONSTRUCTION,
|
||||
_nested_replace_vehicle_widgets, lengthof(_nested_replace_vehicle_widgets)
|
||||
std::begin(_nested_replace_vehicle_widgets), std::end(_nested_replace_vehicle_widgets)
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@
|
||||
* @param entrance Entrance edge.
|
||||
* @return true iff terraforming is allowed.
|
||||
*/
|
||||
static inline bool AutoslopeCheckForEntranceEdge(TileIndex tile, int z_new, Slope tileh_new, DiagDirection entrance)
|
||||
inline bool AutoslopeCheckForEntranceEdge(TileIndex tile, int z_new, Slope tileh_new, DiagDirection entrance)
|
||||
{
|
||||
if (GetTileMaxZ(tile) != z_new + GetSlopeMaxZ(tileh_new)) return false;
|
||||
return ((tileh_new == SLOPE_FLAT) || CanBuildDepotByTileh(entrance, tileh_new));
|
||||
@@ -41,7 +41,7 @@ static inline bool AutoslopeCheckForEntranceEdge(TileIndex tile, int z_new, Slop
|
||||
*
|
||||
* @return true iff autoslope is enabled.
|
||||
*/
|
||||
static inline bool AutoslopeEnabled()
|
||||
inline bool AutoslopeEnabled()
|
||||
{
|
||||
return (_settings_game.construction.autoslope &&
|
||||
(_current_company < MAX_COMPANIES ||
|
||||
|
||||
@@ -42,3 +42,13 @@ void BaseConsist::CopyConsistPropertiesFrom(const BaseConsist *src)
|
||||
}
|
||||
if (HasBit(src->vehicle_flags, VF_SERVINT_IS_CUSTOM)) SetBit(this->vehicle_flags, VF_SERVINT_IS_CUSTOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all the data used for depot unbunching.
|
||||
*/
|
||||
void BaseConsist::ResetDepotUnbunching()
|
||||
{
|
||||
this->depot_unbunching_last_departure = 0;
|
||||
this->depot_unbunching_next_departure = 0;
|
||||
this->round_trip_time = 0;
|
||||
}
|
||||
|
||||
+12
-8
@@ -11,28 +11,32 @@
|
||||
#define BASE_CONSIST_H
|
||||
|
||||
#include "order_type.h"
|
||||
#include "date_type.h"
|
||||
#include <string>
|
||||
#include "timer/timer_game_tick.h"
|
||||
|
||||
/** Various front vehicle properties that are preserved when autoreplacing, using order-backup or switching front engines within a consist. */
|
||||
struct BaseConsist {
|
||||
std::string name; ///< Name of vehicle
|
||||
|
||||
/* Used for timetabling. */
|
||||
uint32 current_order_time; ///< How many ticks have passed since this order started.
|
||||
int32 lateness_counter; ///< How many ticks late (or early if negative) this vehicle is.
|
||||
Date timetable_start; ///< When the vehicle is supposed to start the timetable.
|
||||
TimerGameTick::Ticks current_order_time; ///< How many ticks have passed since this order started.
|
||||
TimerGameTick::Ticks lateness_counter; ///< How many ticks late (or early if negative) this vehicle is.
|
||||
TimerGameTick::TickCounter timetable_start; ///< At what tick of TimerGameTick::counter the vehicle should start its timetable.
|
||||
|
||||
uint16 service_interval; ///< The interval for (automatic) servicing; either in days or %.
|
||||
TimerGameTick::TickCounter depot_unbunching_last_departure; ///< When the vehicle last left its unbunching depot.
|
||||
TimerGameTick::TickCounter depot_unbunching_next_departure; ///< When the vehicle will next try to leave its unbunching depot.
|
||||
TimerGameTick::Ticks round_trip_time; ///< How many ticks for a single circumnavigation of the orders.
|
||||
|
||||
uint16_t service_interval; ///< The interval for (automatic) servicing; either in days or %.
|
||||
|
||||
VehicleOrderID cur_real_order_index;///< The index to the current real (non-implicit) order
|
||||
VehicleOrderID cur_implicit_order_index;///< The index to the current implicit order
|
||||
|
||||
uint16 vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
|
||||
uint16_t vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
|
||||
|
||||
virtual ~BaseConsist() {}
|
||||
virtual ~BaseConsist() = default;
|
||||
|
||||
void CopyConsistPropertiesFrom(const BaseConsist *src);
|
||||
void ResetDepotUnbunching();
|
||||
};
|
||||
|
||||
#endif /* BASE_CONSIST_H */
|
||||
|
||||
+70
-33
@@ -11,10 +11,10 @@
|
||||
#define BASE_MEDIA_BASE_H
|
||||
|
||||
#include "fileio_func.h"
|
||||
#include "core/smallmap_type.hpp"
|
||||
#include "gfx_type.h"
|
||||
#include "textfile_type.h"
|
||||
#include "textfile_gui.h"
|
||||
#include "3rdparty/md5/md5.h"
|
||||
#include <unordered_map>
|
||||
|
||||
/* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */
|
||||
@@ -31,9 +31,9 @@ struct MD5File {
|
||||
CR_NO_FILE, ///< The file did not exist
|
||||
};
|
||||
|
||||
const char *filename; ///< filename
|
||||
uint8 hash[16]; ///< md5 sum of the file
|
||||
const char *missing_warning; ///< warning when this file is missing
|
||||
std::string filename; ///< filename
|
||||
MD5Hash hash; ///< md5 sum of the file
|
||||
std::string missing_warning; ///< warning when this file is missing
|
||||
ChecksumResult check_result; ///< cached result of md5 check
|
||||
|
||||
ChecksumResult CheckMD5(Subdirectory subdir, size_t max_size) const;
|
||||
@@ -59,9 +59,10 @@ struct BaseSet {
|
||||
static const char * const *file_names;
|
||||
|
||||
std::string name; ///< The name of the base set
|
||||
std::string url; ///< URL for information about the base set
|
||||
TranslatedStrings description; ///< Description of the base set
|
||||
uint32 shortname; ///< Four letter short variant of the name
|
||||
uint32 version; ///< The version of this base set
|
||||
uint32_t shortname; ///< Four letter short variant of the name
|
||||
uint32_t version; ///< The version of this base set
|
||||
bool fallback; ///< This set is a fallback set, i.e. it should be used only as last resort
|
||||
|
||||
MD5File files[NUM_FILES]; ///< All files part of this set
|
||||
@@ -73,11 +74,6 @@ struct BaseSet {
|
||||
/** Free everything we allocated */
|
||||
~BaseSet()
|
||||
{
|
||||
for (uint i = 0; i < NUM_FILES; i++) {
|
||||
free(this->files[i].filename);
|
||||
free(this->files[i].missing_warning);
|
||||
}
|
||||
|
||||
delete this->next;
|
||||
}
|
||||
|
||||
@@ -100,7 +96,8 @@ struct BaseSet {
|
||||
return Tnum_files - this->valid_files;
|
||||
}
|
||||
|
||||
bool FillSetDetails(IniFile *ini, const char *path, const char *full_filename, bool allow_empty_filename = true);
|
||||
bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename, bool allow_empty_filename = true);
|
||||
void CopyCompatibleConfig([[maybe_unused]] const T &src) {}
|
||||
|
||||
/**
|
||||
* Get the description for the given ISO code.
|
||||
@@ -110,19 +107,34 @@ struct BaseSet {
|
||||
* @param isocode the isocode to search for
|
||||
* @return the description
|
||||
*/
|
||||
const char *GetDescription(const std::string &isocode) const
|
||||
const std::string &GetDescription(const std::string &isocode) const
|
||||
{
|
||||
if (!isocode.empty()) {
|
||||
/* First the full ISO code */
|
||||
auto desc = this->description.find(isocode);
|
||||
if (desc != this->description.end()) return desc->second.c_str();
|
||||
if (desc != this->description.end()) return desc->second;
|
||||
|
||||
/* Then the first two characters */
|
||||
desc = this->description.find(isocode.substr(0, 2));
|
||||
if (desc != this->description.end()) return desc->second.c_str();
|
||||
if (desc != this->description.end()) return desc->second;
|
||||
}
|
||||
/* Then fall back */
|
||||
return this->description.at(std::string{}).c_str();
|
||||
return this->description.at(std::string{});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string to use when listing this set in the settings window.
|
||||
* If there are no invalid files, then this is just the set name,
|
||||
* otherwise a string is formatted including the number of invalid files.
|
||||
* @return the string to display.
|
||||
*/
|
||||
std::string GetListLabel() const
|
||||
{
|
||||
if (this->GetNumInvalid() == 0) return this->name;
|
||||
|
||||
SetDParamStr(0, this->name);
|
||||
SetDParam(1, this->GetNumInvalid());
|
||||
return GetString(STR_BASESET_STATUS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,17 +154,17 @@ struct BaseSet {
|
||||
/**
|
||||
* Search a textfile file next to this base media.
|
||||
* @param type The type of the textfile to search for.
|
||||
* @return The filename for the textfile, \c nullptr otherwise.
|
||||
* @return The filename for the textfile.
|
||||
*/
|
||||
const char *GetTextfile(TextfileType type) const
|
||||
std::optional<std::string> GetTextfile(TextfileType type) const
|
||||
{
|
||||
for (uint i = 0; i < NUM_FILES; i++) {
|
||||
const char *textfile = ::GetTextfile(type, BASESET_DIR, this->files[i].filename);
|
||||
if (textfile != nullptr) {
|
||||
auto textfile = ::GetTextfile(type, BASESET_DIR, this->files[i].filename);
|
||||
if (textfile.has_value()) {
|
||||
return textfile;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -175,9 +187,6 @@ protected:
|
||||
*/
|
||||
static const char *GetExtension();
|
||||
public:
|
||||
/** The set as saved in the config file. */
|
||||
static std::string ini_set;
|
||||
|
||||
/**
|
||||
* Determine the graphics pack that has to be used.
|
||||
* The one with the most correct files wins.
|
||||
@@ -196,8 +205,10 @@ public:
|
||||
|
||||
static Tbase_set *GetAvailableSets();
|
||||
|
||||
static bool SetSet(const std::string &name);
|
||||
static char *GetSetsList(char *p, const char *last);
|
||||
static bool SetSet(const Tbase_set *set);
|
||||
static bool SetSetByName(const std::string &name);
|
||||
static bool SetSetByShortname(uint32_t shortname);
|
||||
static void GetSetsList(std::back_insert_iterator<std::string> &output_iterator);
|
||||
static int GetNumSets();
|
||||
static int GetIndexOfUsedSet();
|
||||
static const Tbase_set *GetSet(int index);
|
||||
@@ -212,7 +223,6 @@ public:
|
||||
static bool HasSet(const ContentInfo *ci, bool md5sum);
|
||||
};
|
||||
|
||||
template <class Tbase_set> /* static */ std::string BaseMedia<Tbase_set>::ini_set;
|
||||
template <class Tbase_set> /* static */ const Tbase_set *BaseMedia<Tbase_set>::used_set;
|
||||
template <class Tbase_set> /* static */ Tbase_set *BaseMedia<Tbase_set>::available_sets;
|
||||
template <class Tbase_set> /* static */ Tbase_set *BaseMedia<Tbase_set>::duplicate_sets;
|
||||
@@ -244,12 +254,24 @@ enum BlitterType {
|
||||
BLT_32BPP, ///< Base set has both 8 bpp and 32 bpp sprites.
|
||||
};
|
||||
|
||||
struct GRFConfig;
|
||||
|
||||
/** All data of a graphics set. */
|
||||
struct GraphicsSet : BaseSet<GraphicsSet, MAX_GFT, true> {
|
||||
private:
|
||||
mutable std::unique_ptr<GRFConfig> extra_cfg; ///< Parameters for extra GRF
|
||||
public:
|
||||
PaletteType palette; ///< Palette of this graphics set
|
||||
BlitterType blitter; ///< Blitter of this graphics set
|
||||
|
||||
bool FillSetDetails(struct IniFile *ini, const char *path, const char *full_filename);
|
||||
GraphicsSet();
|
||||
~GraphicsSet();
|
||||
|
||||
bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename);
|
||||
GRFConfig *GetExtraConfig() const { return this->extra_cfg.get(); }
|
||||
GRFConfig &GetOrCreateExtraConfig() const;
|
||||
bool IsConfigurable() const;
|
||||
void CopyCompatibleConfig(const GraphicsSet &src);
|
||||
|
||||
static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir);
|
||||
};
|
||||
@@ -257,6 +279,15 @@ struct GraphicsSet : BaseSet<GraphicsSet, MAX_GFT, true> {
|
||||
/** All data/functions related with replacing the base graphics. */
|
||||
class BaseGraphics : public BaseMedia<GraphicsSet> {
|
||||
public:
|
||||
/** Values loaded from config file. */
|
||||
struct Ini {
|
||||
std::string name;
|
||||
uint32_t shortname; ///< unique key for base set
|
||||
uint32_t extra_version; ///< version of the extra GRF
|
||||
std::vector<uint32_t> extra_params; ///< parameters for the extra GRF
|
||||
};
|
||||
static inline Ini ini_data;
|
||||
|
||||
};
|
||||
|
||||
/** All data of a sounds set. */
|
||||
@@ -266,6 +297,9 @@ struct SoundsSet : BaseSet<SoundsSet, 1, true> {
|
||||
/** All data/functions related with replacing the base sounds */
|
||||
class BaseSounds : public BaseMedia<SoundsSet> {
|
||||
public:
|
||||
/** The set as saved in the config file. */
|
||||
static inline std::string ini_set;
|
||||
|
||||
};
|
||||
|
||||
/** Maximum number of songs in the 'class' playlists. */
|
||||
@@ -279,8 +313,8 @@ static const uint NUM_SONGS_AVAILABLE = 1 + NUM_SONG_CLASSES * NUM_SONGS_CLASS;
|
||||
static const uint NUM_SONGS_PLAYLIST = 32;
|
||||
|
||||
/* Functions to read DOS music CAT files, similar to but not quite the same as sound effect CAT files */
|
||||
char *GetMusicCatEntryName(const char *filename, size_t entrynum);
|
||||
byte *GetMusicCatEntryData(const char *filename, size_t entrynum, size_t &entrylen);
|
||||
char *GetMusicCatEntryName(const std::string &filename, size_t entrynum);
|
||||
byte *GetMusicCatEntryData(const std::string &filename, size_t entrynum, size_t &entrylen);
|
||||
|
||||
enum MusicTrackType {
|
||||
MTT_STANDARDMIDI, ///< Standard MIDI file
|
||||
@@ -289,9 +323,9 @@ enum MusicTrackType {
|
||||
|
||||
/** Metadata about a music track. */
|
||||
struct MusicSongInfo {
|
||||
char songname[32]; ///< name of song displayed in UI
|
||||
std::string songname; ///< name of song displayed in UI
|
||||
byte tracknr; ///< track number of song displayed in UI
|
||||
const char *filename; ///< file on disk containing song (when used in MusicSet class, this pointer is owned by MD5File object for the file)
|
||||
std::string filename; ///< file on disk containing song (when used in MusicSet class)
|
||||
MusicTrackType filetype; ///< decoder required for song file
|
||||
int cat_index; ///< entry index in CAT file, for filetype==MTT_MPSMIDI
|
||||
bool loop; ///< song should play in a tight loop if possible, never ending
|
||||
@@ -306,12 +340,15 @@ struct MusicSet : BaseSet<MusicSet, NUM_SONGS_AVAILABLE, false> {
|
||||
/** Number of valid songs in set. */
|
||||
byte num_available;
|
||||
|
||||
bool FillSetDetails(struct IniFile *ini, const char *path, const char *full_filename);
|
||||
bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename);
|
||||
};
|
||||
|
||||
/** All data/functions related with replacing the base music */
|
||||
class BaseMusic : public BaseMedia<MusicSet> {
|
||||
public:
|
||||
/** The set as saved in the config file. */
|
||||
static inline std::string ini_set;
|
||||
|
||||
};
|
||||
|
||||
#endif /* BASE_MEDIA_BASE_H */
|
||||
|
||||
+98
-60
@@ -14,13 +14,16 @@
|
||||
#include "debug.h"
|
||||
#include "ini_type.h"
|
||||
#include "string_func.h"
|
||||
#include "error_func.h"
|
||||
|
||||
extern void CheckExternalFiles();
|
||||
|
||||
/**
|
||||
* Try to read a single piece of metadata and return false if it doesn't exist.
|
||||
* @param name the name of the item to fetch.
|
||||
*/
|
||||
#define fetch_metadata(name) \
|
||||
item = metadata->GetItem(name, false); \
|
||||
item = metadata->GetItem(name); \
|
||||
if (item == nullptr || !item->value.has_value() || item->value->empty()) { \
|
||||
Debug(grf, 0, "Base " SET_TYPE "set detail loading: {} field missing.", name); \
|
||||
Debug(grf, 0, " Is {} readable for the user running OpenTTD?", full_filename); \
|
||||
@@ -36,10 +39,15 @@
|
||||
* @return true if loading was successful.
|
||||
*/
|
||||
template <class T, size_t Tnum_files, bool Tsearch_in_tars>
|
||||
bool BaseSet<T, Tnum_files, Tsearch_in_tars>::FillSetDetails(IniFile *ini, const char *path, const char *full_filename, bool allow_empty_filename)
|
||||
bool BaseSet<T, Tnum_files, Tsearch_in_tars>::FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename, bool allow_empty_filename)
|
||||
{
|
||||
IniGroup *metadata = ini->GetGroup("metadata");
|
||||
IniItem *item;
|
||||
const IniGroup *metadata = ini.GetGroup("metadata");
|
||||
if (metadata == nullptr) {
|
||||
Debug(grf, 0, "Base " SET_TYPE "set detail loading: metadata missing.");
|
||||
Debug(grf, 0, " Is {} readable for the user running OpenTTD?", full_filename);
|
||||
return false;
|
||||
}
|
||||
const IniItem *item;
|
||||
|
||||
fetch_metadata("name");
|
||||
this->name = *item->value;
|
||||
@@ -47,56 +55,59 @@ bool BaseSet<T, Tnum_files, Tsearch_in_tars>::FillSetDetails(IniFile *ini, const
|
||||
fetch_metadata("description");
|
||||
this->description[std::string{}] = *item->value;
|
||||
|
||||
/* Add the translations of the descriptions too. */
|
||||
for (const IniItem *item = metadata->item; item != nullptr; item = item->next) {
|
||||
if (item->name.compare(0, 12, "description.") != 0) continue;
|
||||
item = metadata->GetItem("url");
|
||||
if (item != nullptr) this->url = *item->value;
|
||||
|
||||
this->description[item->name.substr(12)] = item->value.value_or("");
|
||||
/* Add the translations of the descriptions too. */
|
||||
for (const IniItem &titem : metadata->items) {
|
||||
if (titem.name.compare(0, 12, "description.") != 0) continue;
|
||||
|
||||
this->description[titem.name.substr(12)] = titem.value.value_or("");
|
||||
}
|
||||
|
||||
fetch_metadata("shortname");
|
||||
for (uint i = 0; (*item->value)[i] != '\0' && i < 4; i++) {
|
||||
this->shortname |= ((uint8)(*item->value)[i]) << (i * 8);
|
||||
this->shortname |= ((uint8_t)(*item->value)[i]) << (i * 8);
|
||||
}
|
||||
|
||||
fetch_metadata("version");
|
||||
this->version = atoi(item->value->c_str());
|
||||
|
||||
item = metadata->GetItem("fallback", false);
|
||||
item = metadata->GetItem("fallback");
|
||||
this->fallback = (item != nullptr && item->value && *item->value != "0" && *item->value != "false");
|
||||
|
||||
/* For each of the file types we want to find the file, MD5 checksums and warning messages. */
|
||||
IniGroup *files = ini->GetGroup("files");
|
||||
IniGroup *md5s = ini->GetGroup("md5s");
|
||||
IniGroup *origin = ini->GetGroup("origin");
|
||||
const IniGroup *files = ini.GetGroup("files");
|
||||
const IniGroup *md5s = ini.GetGroup("md5s");
|
||||
const IniGroup *origin = ini.GetGroup("origin");
|
||||
for (uint i = 0; i < Tnum_files; i++) {
|
||||
MD5File *file = &this->files[i];
|
||||
/* Find the filename first. */
|
||||
item = files->GetItem(BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names[i], false);
|
||||
item = files != nullptr ? files->GetItem(BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names[i]) : nullptr;
|
||||
if (item == nullptr || (!item->value.has_value() && !allow_empty_filename)) {
|
||||
Debug(grf, 0, "No " SET_TYPE " file for: {} (in {})", BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names[i], full_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!item->value.has_value()) {
|
||||
file->filename = nullptr;
|
||||
file->filename.clear();
|
||||
/* If we list no file, that file must be valid */
|
||||
this->valid_files++;
|
||||
this->found_files++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *filename = item->value->c_str();
|
||||
file->filename = str_fmt("%s%s", path, filename);
|
||||
const std::string &filename = item->value.value();
|
||||
file->filename = path + filename;
|
||||
|
||||
/* Then find the MD5 checksum */
|
||||
item = md5s->GetItem(filename, false);
|
||||
item = md5s != nullptr ? md5s->GetItem(filename) : nullptr;
|
||||
if (item == nullptr || !item->value.has_value()) {
|
||||
Debug(grf, 0, "No MD5 checksum specified for: {} (in {})", filename, full_filename);
|
||||
return false;
|
||||
}
|
||||
const char *c = item->value->c_str();
|
||||
for (uint i = 0; i < sizeof(file->hash) * 2; i++, c++) {
|
||||
for (size_t i = 0; i < file->hash.size() * 2; i++, c++) {
|
||||
uint j;
|
||||
if ('0' <= *c && *c <= '9') {
|
||||
j = *c - '0';
|
||||
@@ -116,13 +127,13 @@ bool BaseSet<T, Tnum_files, Tsearch_in_tars>::FillSetDetails(IniFile *ini, const
|
||||
}
|
||||
|
||||
/* Then find the warning message when the file's missing */
|
||||
item = origin->GetItem(filename, false);
|
||||
if (item == nullptr) item = origin->GetItem("default", false);
|
||||
item = origin != nullptr ? origin->GetItem(filename) : nullptr;
|
||||
if (item == nullptr) item = origin != nullptr ? origin->GetItem("default") : nullptr;
|
||||
if (item == nullptr || !item->value.has_value()) {
|
||||
Debug(grf, 1, "No origin warning message specified for: {}", filename);
|
||||
file->missing_warning = stredup("");
|
||||
file->missing_warning.clear();
|
||||
} else {
|
||||
file->missing_warning = stredup(item->value->c_str());
|
||||
file->missing_warning = item->value.value();
|
||||
}
|
||||
|
||||
file->check_result = T::CheckMD5(file, BASESET_DIR);
|
||||
@@ -150,15 +161,15 @@ bool BaseSet<T, Tnum_files, Tsearch_in_tars>::FillSetDetails(IniFile *ini, const
|
||||
}
|
||||
|
||||
template <class Tbase_set>
|
||||
bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename)
|
||||
bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_length, const std::string &)
|
||||
{
|
||||
bool ret = false;
|
||||
Debug(grf, 1, "Checking {} for base " SET_TYPE " set", filename);
|
||||
|
||||
Tbase_set *set = new Tbase_set();
|
||||
IniFile *ini = new IniFile();
|
||||
IniFile ini{};
|
||||
std::string path{ filename, basepath_length };
|
||||
ini->LoadFromDisk(path, BASESET_DIR);
|
||||
ini.LoadFromDisk(path, BASESET_DIR);
|
||||
|
||||
auto psep = path.rfind(PATHSEPCHAR);
|
||||
if (psep != std::string::npos) {
|
||||
@@ -167,7 +178,7 @@ bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_
|
||||
path.clear();
|
||||
}
|
||||
|
||||
if (set->FillSetDetails(ini, path.c_str(), filename.c_str())) {
|
||||
if (set->FillSetDetails(ini, path, filename)) {
|
||||
Tbase_set *duplicate = nullptr;
|
||||
for (Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != nullptr; c = c->next) {
|
||||
if (c->name == set->name || c->shortname == set->shortname) {
|
||||
@@ -190,6 +201,9 @@ bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_
|
||||
*prev = set;
|
||||
set->next = duplicate->next;
|
||||
|
||||
/* Keep baseset configuration, if compatible */
|
||||
set->CopyCompatibleConfig(*duplicate);
|
||||
|
||||
/* If the duplicate set is currently used (due to rescanning this can happen)
|
||||
* update the currently used set to the new one. This will 'lie' about the
|
||||
* version number until a new game is started which isn't a big problem */
|
||||
@@ -215,31 +229,61 @@ bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_
|
||||
delete set;
|
||||
}
|
||||
|
||||
delete ini;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the set to be used.
|
||||
* @param set the set to use
|
||||
* @return true if it could be loaded
|
||||
*/
|
||||
template <class Tbase_set>
|
||||
/* static */ bool BaseMedia<Tbase_set>::SetSet(const Tbase_set *set)
|
||||
{
|
||||
if (set == nullptr) {
|
||||
if (!BaseMedia<Tbase_set>::DetermineBestSet()) return false;
|
||||
} else {
|
||||
BaseMedia<Tbase_set>::used_set = set;
|
||||
}
|
||||
CheckExternalFiles();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the set to be used.
|
||||
* @param name of the set to use
|
||||
* @return true if it could be loaded
|
||||
*/
|
||||
template <class Tbase_set>
|
||||
/* static */ bool BaseMedia<Tbase_set>::SetSet(const std::string &name)
|
||||
/* static */ bool BaseMedia<Tbase_set>::SetSetByName(const std::string &name)
|
||||
{
|
||||
extern void CheckExternalFiles();
|
||||
|
||||
if (name.empty()) {
|
||||
if (!BaseMedia<Tbase_set>::DetermineBestSet()) return false;
|
||||
CheckExternalFiles();
|
||||
return true;
|
||||
return SetSet(nullptr);
|
||||
}
|
||||
|
||||
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != nullptr; s = s->next) {
|
||||
if (name == s->name) {
|
||||
BaseMedia<Tbase_set>::used_set = s;
|
||||
CheckExternalFiles();
|
||||
return true;
|
||||
return SetSet(s);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the set to be used.
|
||||
* @param shortname of the set to use
|
||||
* @return true if it could be loaded
|
||||
*/
|
||||
template <class Tbase_set>
|
||||
/* static */ bool BaseMedia<Tbase_set>::SetSetByShortname(uint32_t shortname)
|
||||
{
|
||||
if (shortname == 0) {
|
||||
return SetSet(nullptr);
|
||||
}
|
||||
|
||||
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != nullptr; s = s->next) {
|
||||
if (shortname == s->shortname) {
|
||||
return SetSet(s);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -247,31 +291,27 @@ template <class Tbase_set>
|
||||
|
||||
/**
|
||||
* Returns a list with the sets.
|
||||
* @param p where to print to
|
||||
* @param last the last character to print to
|
||||
* @return the last printed character
|
||||
* @param output_iterator The iterator to write the string to.
|
||||
*/
|
||||
template <class Tbase_set>
|
||||
/* static */ char *BaseMedia<Tbase_set>::GetSetsList(char *p, const char *last)
|
||||
/* static */ void BaseMedia<Tbase_set>::GetSetsList(std::back_insert_iterator<std::string> &output_iterator)
|
||||
{
|
||||
p += seprintf(p, last, "List of " SET_TYPE " sets:\n");
|
||||
fmt::format_to(output_iterator, "List of " SET_TYPE " sets:\n");
|
||||
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != nullptr; s = s->next) {
|
||||
p += seprintf(p, last, "%18s: %s", s->name.c_str(), s->GetDescription({}));
|
||||
fmt::format_to(output_iterator, "{:>18}: {}", s->name, s->GetDescription({}));
|
||||
int invalid = s->GetNumInvalid();
|
||||
if (invalid != 0) {
|
||||
int missing = s->GetNumMissing();
|
||||
if (missing == 0) {
|
||||
p += seprintf(p, last, " (%i corrupt file%s)\n", invalid, invalid == 1 ? "" : "s");
|
||||
fmt::format_to(output_iterator, " ({} corrupt file{})\n", invalid, invalid == 1 ? "" : "s");
|
||||
} else {
|
||||
p += seprintf(p, last, " (unusable: %i missing file%s)\n", missing, missing == 1 ? "" : "s");
|
||||
fmt::format_to(output_iterator, " (unusable: {} missing file{})\n", missing, missing == 1 ? "" : "s");
|
||||
}
|
||||
} else {
|
||||
p += seprintf(p, last, "\n");
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
}
|
||||
p += seprintf(p, last, "\n");
|
||||
|
||||
return p;
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
|
||||
#include "network/core/tcp_content_type.h"
|
||||
@@ -282,16 +322,13 @@ template <class Tbase_set> const char *TryGetBaseSetFile(const ContentInfo *ci,
|
||||
if (s->GetNumMissing() != 0) continue;
|
||||
|
||||
if (s->shortname != ci->unique_id) continue;
|
||||
if (!md5sum) return s->files[0].filename;
|
||||
if (!md5sum) return s->files[0].filename.c_str();
|
||||
|
||||
byte md5[16];
|
||||
memset(md5, 0, sizeof(md5));
|
||||
MD5Hash md5;
|
||||
for (uint i = 0; i < Tbase_set::NUM_FILES; i++) {
|
||||
for (uint j = 0; j < sizeof(md5); j++) {
|
||||
md5[j] ^= s->files[i].hash[j];
|
||||
}
|
||||
md5 ^= s->files[i].hash;
|
||||
}
|
||||
if (memcmp(md5, ci->md5sum, sizeof(md5)) == 0) return s->files[0].filename;
|
||||
if (md5 == ci->md5sum) return s->files[0].filename.c_str();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -346,7 +383,7 @@ template <class Tbase_set>
|
||||
if (index == 0) return s;
|
||||
index--;
|
||||
}
|
||||
error("Base" SET_TYPE "::GetSet(): index %d out of range", index);
|
||||
FatalError("Base" SET_TYPE "::GetSet(): index {} out of range", index);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,12 +412,13 @@ template <class Tbase_set>
|
||||
* @param set_type the type of the BaseSet to instantiate
|
||||
*/
|
||||
#define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \
|
||||
template std::string repl_type::ini_set; \
|
||||
template const char *repl_type::GetExtension(); \
|
||||
template bool repl_type::AddFile(const std::string &filename, size_t pathlength, const std::string &tar_filename); \
|
||||
template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \
|
||||
template bool repl_type::SetSet(const std::string &name); \
|
||||
template char *repl_type::GetSetsList(char *p, const char *last); \
|
||||
template bool repl_type::SetSet(const set_type *set); \
|
||||
template bool repl_type::SetSetByName(const std::string &name); \
|
||||
template bool repl_type::SetSetByShortname(uint32_t shortname); \
|
||||
template void repl_type::GetSetsList(std::back_insert_iterator<std::string> &output_iterator); \
|
||||
template int repl_type::GetNumSets(); \
|
||||
template int repl_type::GetIndexOfUsedSet(); \
|
||||
template const set_type *repl_type::GetSet(int index); \
|
||||
|
||||
+52
-11
@@ -14,16 +14,28 @@
|
||||
#include "command_type.h"
|
||||
#include "viewport_type.h"
|
||||
#include "station_map.h"
|
||||
#include "timer/timer_game_calendar.h"
|
||||
|
||||
typedef Pool<BaseStation, StationID, 32, 64000> StationPool;
|
||||
extern StationPool _station_pool;
|
||||
|
||||
struct StationSpecList {
|
||||
const StationSpec *spec;
|
||||
uint32 grfid; ///< GRF ID of this custom station
|
||||
uint8 localidx; ///< Station ID within GRF of station
|
||||
uint32_t grfid; ///< GRF ID of this custom station
|
||||
uint16_t localidx; ///< Station ID within GRF of station
|
||||
};
|
||||
|
||||
struct RoadStopSpecList {
|
||||
const RoadStopSpec *spec;
|
||||
uint32_t grfid; ///< GRF ID of this custom road stop
|
||||
uint16_t localidx; ///< Station ID within GRF of road stop
|
||||
};
|
||||
|
||||
struct RoadStopTileData {
|
||||
TileIndex tile;
|
||||
uint8_t random_bits;
|
||||
uint8_t animation_frame;
|
||||
};
|
||||
|
||||
/** StationRect - used to track station spread out rectangle - cheaper than scanning whole map */
|
||||
struct StationRect : public Rect {
|
||||
@@ -62,18 +74,23 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
|
||||
Owner owner; ///< The owner of this station
|
||||
StationFacility facilities; ///< The facilities that this station has
|
||||
|
||||
std::vector<StationSpecList> speclist; ///< List of rail station specs of this station.
|
||||
std::vector<StationSpecList> speclist; ///< List of rail station specs of this station.
|
||||
std::vector<RoadStopSpecList> roadstop_speclist; ///< List of road stop specs of this station
|
||||
|
||||
Date build_date; ///< Date of construction
|
||||
TimerGameCalendar::Date build_date; ///< Date of construction
|
||||
|
||||
uint16 random_bits; ///< Random bits assigned to this station
|
||||
uint16_t random_bits; ///< Random bits assigned to this station
|
||||
byte waiting_triggers; ///< Waiting triggers (NewGRF) for this station
|
||||
uint8 cached_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
|
||||
CargoTypes cached_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask
|
||||
uint8_t cached_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
|
||||
uint8_t cached_roadstop_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask for road stops, used to determine if trigger processing should happen.
|
||||
CargoTypes cached_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask
|
||||
CargoTypes cached_roadstop_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask for road stops
|
||||
|
||||
TileArea train_station; ///< Tile area the train 'station' part covers
|
||||
StationRect rect; ///< NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions
|
||||
|
||||
std::vector<RoadStopTileData> custom_roadstop_tile_data; ///< List of custom road stop tile data
|
||||
|
||||
/**
|
||||
* Initialize the base station.
|
||||
* @param tile The location of the station sign
|
||||
@@ -101,18 +118,18 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
|
||||
* @param available will return false if ever the variable asked for does not exist
|
||||
* @return the value stored in the corresponding variable
|
||||
*/
|
||||
virtual uint32 GetNewGRFVariable(const struct ResolverObject &object, byte variable, byte parameter, bool *available) const = 0;
|
||||
virtual uint32_t GetNewGRFVariable(const struct ResolverObject &object, byte variable, byte parameter, bool *available) const = 0;
|
||||
|
||||
/**
|
||||
* Update the coordinated of the sign (as shown in the viewport).
|
||||
*/
|
||||
virtual void UpdateVirtCoord() = 0;
|
||||
|
||||
inline const char *GetCachedName() const
|
||||
inline const std::string &GetCachedName() const
|
||||
{
|
||||
if (!this->name.empty()) return this->name.c_str();
|
||||
if (!this->name.empty()) return this->name;
|
||||
if (this->cached_name.empty()) this->FillCachedName();
|
||||
return this->cached_name.c_str();
|
||||
return this->cached_name;
|
||||
}
|
||||
|
||||
virtual void MoveSign(TileIndex new_xy)
|
||||
@@ -167,6 +184,30 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
|
||||
return (this->facilities & ~FACIL_WAYPOINT) != 0;
|
||||
}
|
||||
|
||||
inline byte GetRoadStopRandomBits(TileIndex tile) const
|
||||
{
|
||||
for (const RoadStopTileData &tile_data : this->custom_roadstop_tile_data) {
|
||||
if (tile_data.tile == tile) return tile_data.random_bits;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline byte GetRoadStopAnimationFrame(TileIndex tile) const
|
||||
{
|
||||
for (const RoadStopTileData &tile_data : this->custom_roadstop_tile_data) {
|
||||
if (tile_data.tile == tile) return tile_data.animation_frame;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void SetRoadStopTileData(TileIndex tile, byte data, bool animation);
|
||||
|
||||
public:
|
||||
inline void SetRoadStopRandomBits(TileIndex tile, byte random_bits) { this->SetRoadStopTileData(tile, random_bits, false); }
|
||||
inline void SetRoadStopAnimationFrame(TileIndex tile, byte frame) { this->SetRoadStopTileData(tile, frame, true); }
|
||||
void RemoveRoadStopTileData(TileIndex tile);
|
||||
|
||||
static void PostDestructor(size_t index);
|
||||
|
||||
private:
|
||||
|
||||
+3
-4
@@ -10,7 +10,6 @@
|
||||
#ifndef BITMAP_TYPE_HPP
|
||||
#define BITMAP_TYPE_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
/** Represents a tile area containing containing individually set tiles.
|
||||
* Each tile must be contained within the preallocated area.
|
||||
@@ -117,7 +116,7 @@ public:
|
||||
if (!this->bitmap->HasTile(TileIndex(this->tile))) ++(*this);
|
||||
}
|
||||
|
||||
inline TileIterator& operator ++()
|
||||
inline TileIterator& operator ++() override
|
||||
{
|
||||
(*this).OrthogonalTileIterator::operator++();
|
||||
while (this->tile != INVALID_TILE && !this->bitmap->HasTile(TileIndex(this->tile))) {
|
||||
@@ -126,9 +125,9 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual TileIterator *Clone() const
|
||||
std::unique_ptr<TileIterator> Clone() const override
|
||||
{
|
||||
return new BitmapTileIterator(*this);
|
||||
return std::make_unique<BitmapTileIterator>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+64
-48
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../video/video_driver.hpp"
|
||||
#include "../palette_func.h"
|
||||
#include "32bpp_anim.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
@@ -30,26 +31,26 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
||||
const SpriteData *src = (const SpriteData *)bp->sprite;
|
||||
|
||||
const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
|
||||
const uint16 *src_n = (const uint16 *)(src->data + src->offset[zoom][1]);
|
||||
const uint16_t *src_n = (const uint16_t *)(src->data + src->offset[zoom][1]);
|
||||
|
||||
for (uint i = bp->skip_top; i != 0; i--) {
|
||||
src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
|
||||
src_n = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n);
|
||||
src_px = (const Colour *)((const byte *)src_px + *(const uint32_t *)src_px);
|
||||
src_n = (const uint16_t *)((const byte *)src_n + *(const uint32_t *)src_n);
|
||||
}
|
||||
|
||||
Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left;
|
||||
uint16 *anim = this->anim_buf + this->ScreenToAnimOffset((uint32 *)bp->dst) + bp->top * this->anim_buf_pitch + bp->left;
|
||||
uint16_t *anim = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)bp->dst) + bp->top * this->anim_buf_pitch + bp->left;
|
||||
|
||||
const byte *remap = bp->remap; // store so we don't have to access it via bp every time
|
||||
|
||||
for (int y = 0; y < bp->height; y++) {
|
||||
Colour *dst_ln = dst + bp->pitch;
|
||||
uint16 *anim_ln = anim + this->anim_buf_pitch;
|
||||
uint16_t *anim_ln = anim + this->anim_buf_pitch;
|
||||
|
||||
const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
|
||||
const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32_t *)src_px);
|
||||
src_px++;
|
||||
|
||||
const uint16 *src_n_ln = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n);
|
||||
const uint16_t *src_n_ln = (const uint16_t *)((const byte *)src_n + *(const uint32_t *)src_n);
|
||||
src_n += 2;
|
||||
|
||||
Colour *dst_end = dst + bp->skip_left;
|
||||
@@ -144,7 +145,7 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
||||
do {
|
||||
uint m = *src_n;
|
||||
if (m == 0) {
|
||||
uint8 g = MakeDark(src_px->r, src_px->g, src_px->b);
|
||||
uint8_t g = MakeDark(src_px->r, src_px->g, src_px->b);
|
||||
*dst = ComposeColourRGBA(g, g, g, src_px->a, *dst);
|
||||
*anim = 0;
|
||||
} else {
|
||||
@@ -162,7 +163,7 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
||||
uint m = *src_n;
|
||||
if (m == 0) {
|
||||
if (src_px->a != 0) {
|
||||
uint8 g = MakeDark(src_px->r, src_px->g, src_px->b);
|
||||
uint8_t g = MakeDark(src_px->r, src_px->g, src_px->b);
|
||||
*dst = ComposeColourRGBA(g, g, g, src_px->a, *dst);
|
||||
*anim = 0;
|
||||
}
|
||||
@@ -190,10 +191,6 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
||||
break;
|
||||
|
||||
case BM_TRANSPARENT:
|
||||
/* TODO -- We make an assumption here that the remap in fact is transparency, not some colour.
|
||||
* This is never a problem with the code we produce, but newgrfs can make it fail... or at least:
|
||||
* we produce a result the newgrf maker didn't expect ;) */
|
||||
|
||||
/* Make the current colour a bit more black, so it looks like this image is transparent */
|
||||
src_n += n;
|
||||
if (src_px->a == 255) {
|
||||
@@ -215,6 +212,24 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
||||
}
|
||||
break;
|
||||
|
||||
case BM_TRANSPARENT_REMAP:
|
||||
/* Apply custom transparency remap. */
|
||||
src_n += n;
|
||||
if (src_px->a != 0) {
|
||||
src_px += n;
|
||||
do {
|
||||
*dst = this->LookupColourInPalette(remap[GetNearestColourIndex(*dst)]);
|
||||
*anim = 0;
|
||||
anim++;
|
||||
dst++;
|
||||
} while (--n != 0);
|
||||
} else {
|
||||
dst += n;
|
||||
anim += n;
|
||||
src_px += n;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
@@ -264,6 +279,7 @@ void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomL
|
||||
case BM_NORMAL: Draw<BM_NORMAL> (bp, zoom); return;
|
||||
case BM_COLOUR_REMAP: Draw<BM_COLOUR_REMAP>(bp, zoom); return;
|
||||
case BM_TRANSPARENT: Draw<BM_TRANSPARENT> (bp, zoom); return;
|
||||
case BM_TRANSPARENT_REMAP: Draw<BM_TRANSPARENT_REMAP>(bp, zoom); return;
|
||||
case BM_CRASH_REMAP: Draw<BM_CRASH_REMAP> (bp, zoom); return;
|
||||
case BM_BLACK_REMAP: Draw<BM_BLACK_REMAP> (bp, zoom); return;
|
||||
}
|
||||
@@ -278,7 +294,7 @@ void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height,
|
||||
}
|
||||
|
||||
Colour *udst = (Colour *)dst;
|
||||
uint16 *anim = this->anim_buf + this->ScreenToAnimOffset((uint32 *)dst);
|
||||
uint16_t *anim = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)dst);
|
||||
|
||||
if (pal == PALETTE_TO_TRANSPARENT) {
|
||||
do {
|
||||
@@ -310,17 +326,17 @@ void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height,
|
||||
Debug(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal);
|
||||
}
|
||||
|
||||
void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8 colour)
|
||||
void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8_t colour)
|
||||
{
|
||||
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour);
|
||||
|
||||
/* Set the colour in the anim-buffer too, if we are rendering to the screen */
|
||||
if (_screen_disable_anim) return;
|
||||
|
||||
this->anim_buf[this->ScreenToAnimOffset((uint32 *)video) + x + y * this->anim_buf_pitch] = colour | (DEFAULT_BRIGHTNESS << 8);
|
||||
this->anim_buf[this->ScreenToAnimOffset((uint32_t *)video) + x + y * this->anim_buf_pitch] = colour | (DEFAULT_BRIGHTNESS << 8);
|
||||
}
|
||||
|
||||
void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
|
||||
void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash)
|
||||
{
|
||||
const Colour c = LookupColourInPalette(colour);
|
||||
|
||||
@@ -329,8 +345,8 @@ void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
|
||||
*((Colour *)video + x + y * _screen.pitch) = c;
|
||||
});
|
||||
} else {
|
||||
uint16 * const offset_anim_buf = this->anim_buf + this->ScreenToAnimOffset((uint32 *)video);
|
||||
const uint16 anim_colour = colour | (DEFAULT_BRIGHTNESS << 8);
|
||||
uint16_t * const offset_anim_buf = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)video);
|
||||
const uint16_t anim_colour = colour | (DEFAULT_BRIGHTNESS << 8);
|
||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
|
||||
*((Colour *)video + x + y * _screen.pitch) = c;
|
||||
offset_anim_buf[x + y * this->anim_buf_pitch] = anim_colour;
|
||||
@@ -338,7 +354,7 @@ void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
|
||||
}
|
||||
}
|
||||
|
||||
void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colour)
|
||||
void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8_t colour)
|
||||
{
|
||||
if (_screen_disable_anim) {
|
||||
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
|
||||
@@ -347,11 +363,11 @@ void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colou
|
||||
}
|
||||
|
||||
Colour colour32 = LookupColourInPalette(colour);
|
||||
uint16 *anim_line = this->ScreenToAnimOffset((uint32 *)video) + this->anim_buf;
|
||||
uint16_t *anim_line = this->ScreenToAnimOffset((uint32_t *)video) + this->anim_buf;
|
||||
|
||||
do {
|
||||
Colour *dst = (Colour *)video;
|
||||
uint16 *anim = anim_line;
|
||||
uint16_t *anim = anim_line;
|
||||
|
||||
for (int i = width; i > 0; i--) {
|
||||
*dst = colour32;
|
||||
@@ -360,7 +376,7 @@ void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colou
|
||||
dst++;
|
||||
anim++;
|
||||
}
|
||||
video = (uint32 *)video + _screen.pitch;
|
||||
video = (uint32_t *)video + _screen.pitch;
|
||||
anim_line += this->anim_buf_pitch;
|
||||
} while (--height);
|
||||
}
|
||||
@@ -368,22 +384,22 @@ void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colou
|
||||
void Blitter_32bppAnim::CopyFromBuffer(void *video, const void *src, int width, int height)
|
||||
{
|
||||
assert(!_screen_disable_anim);
|
||||
assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
|
||||
assert(video >= _screen.dst_ptr && video <= (uint32_t *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
|
||||
Colour *dst = (Colour *)video;
|
||||
const uint32 *usrc = (const uint32 *)src;
|
||||
uint16 *anim_line = this->ScreenToAnimOffset((uint32 *)video) + this->anim_buf;
|
||||
const uint32_t *usrc = (const uint32_t *)src;
|
||||
uint16_t *anim_line = this->ScreenToAnimOffset((uint32_t *)video) + this->anim_buf;
|
||||
|
||||
for (; height > 0; height--) {
|
||||
/* We need to keep those for palette animation. */
|
||||
Colour *dst_pal = dst;
|
||||
uint16 *anim_pal = anim_line;
|
||||
uint16_t *anim_pal = anim_line;
|
||||
|
||||
memcpy(static_cast<void *>(dst), usrc, width * sizeof(uint32));
|
||||
memcpy(static_cast<void *>(dst), usrc, width * sizeof(uint32_t));
|
||||
usrc += width;
|
||||
dst += _screen.pitch;
|
||||
/* Copy back the anim-buffer */
|
||||
memcpy(anim_line, usrc, width * sizeof(uint16));
|
||||
usrc = (const uint32 *)((const uint16 *)usrc + width);
|
||||
memcpy(anim_line, usrc, width * sizeof(uint16_t));
|
||||
usrc = (const uint32_t *)&((const uint16_t *)usrc)[width];
|
||||
anim_line += this->anim_buf_pitch;
|
||||
|
||||
/* Okay, it is *very* likely that the image we stored is using
|
||||
@@ -408,21 +424,21 @@ void Blitter_32bppAnim::CopyFromBuffer(void *video, const void *src, int width,
|
||||
void Blitter_32bppAnim::CopyToBuffer(const void *video, void *dst, int width, int height)
|
||||
{
|
||||
assert(!_screen_disable_anim);
|
||||
assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
|
||||
uint32 *udst = (uint32 *)dst;
|
||||
const uint32 *src = (const uint32 *)video;
|
||||
assert(video >= _screen.dst_ptr && video <= (uint32_t *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
|
||||
uint32_t *udst = (uint32_t *)dst;
|
||||
const uint32_t *src = (const uint32_t *)video;
|
||||
|
||||
if (this->anim_buf == nullptr) return;
|
||||
|
||||
const uint16 *anim_line = this->ScreenToAnimOffset((const uint32 *)video) + this->anim_buf;
|
||||
const uint16_t *anim_line = this->ScreenToAnimOffset((const uint32_t *)video) + this->anim_buf;
|
||||
|
||||
for (; height > 0; height--) {
|
||||
memcpy(udst, src, width * sizeof(uint32));
|
||||
memcpy(udst, src, width * sizeof(uint32_t));
|
||||
src += _screen.pitch;
|
||||
udst += width;
|
||||
/* Copy the anim-buffer */
|
||||
memcpy(udst, anim_line, width * sizeof(uint16));
|
||||
udst = (uint32 *)((uint16 *)udst + width);
|
||||
memcpy(udst, anim_line, width * sizeof(uint16_t));
|
||||
udst = (uint32_t *)&((uint16_t *)udst)[width];
|
||||
anim_line += this->anim_buf_pitch;
|
||||
}
|
||||
}
|
||||
@@ -430,8 +446,8 @@ void Blitter_32bppAnim::CopyToBuffer(const void *video, void *dst, int width, in
|
||||
void Blitter_32bppAnim::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y)
|
||||
{
|
||||
assert(!_screen_disable_anim);
|
||||
assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
|
||||
uint16 *dst, *src;
|
||||
assert(video >= _screen.dst_ptr && video <= (uint32_t *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch);
|
||||
uint16_t *dst, *src;
|
||||
|
||||
/* We need to scroll the anim-buffer too */
|
||||
if (scroll_y > 0) {
|
||||
@@ -448,7 +464,7 @@ void Blitter_32bppAnim::ScrollBuffer(void *video, int &left, int &top, int &widt
|
||||
uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x);
|
||||
uint th = height - scroll_y;
|
||||
for (; th > 0; th--) {
|
||||
memcpy(dst, src, tw * sizeof(uint16));
|
||||
memcpy(dst, src, tw * sizeof(uint16_t));
|
||||
src -= this->anim_buf_pitch;
|
||||
dst -= this->anim_buf_pitch;
|
||||
}
|
||||
@@ -469,7 +485,7 @@ void Blitter_32bppAnim::ScrollBuffer(void *video, int &left, int &top, int &widt
|
||||
uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x);
|
||||
uint th = height + scroll_y;
|
||||
for (; th > 0; th--) {
|
||||
memmove(dst, src, tw * sizeof(uint16));
|
||||
memmove(dst, src, tw * sizeof(uint16_t));
|
||||
src += this->anim_buf_pitch;
|
||||
dst += this->anim_buf_pitch;
|
||||
}
|
||||
@@ -478,9 +494,9 @@ void Blitter_32bppAnim::ScrollBuffer(void *video, int &left, int &top, int &widt
|
||||
Blitter_32bppBase::ScrollBuffer(video, left, top, width, height, scroll_x, scroll_y);
|
||||
}
|
||||
|
||||
int Blitter_32bppAnim::BufferSize(int width, int height)
|
||||
size_t Blitter_32bppAnim::BufferSize(uint width, uint height)
|
||||
{
|
||||
return width * height * (sizeof(uint32) + sizeof(uint16));
|
||||
return (sizeof(uint32_t) + sizeof(uint16_t)) * width * height;
|
||||
}
|
||||
|
||||
void Blitter_32bppAnim::PaletteAnimate(const Palette &palette)
|
||||
@@ -493,7 +509,7 @@ void Blitter_32bppAnim::PaletteAnimate(const Palette &palette)
|
||||
* Especially when going between toyland and non-toyland. */
|
||||
assert(this->palette.first_dirty == PALETTE_ANIM_START || this->palette.first_dirty == 0);
|
||||
|
||||
const uint16 *anim = this->anim_buf;
|
||||
const uint16_t *anim = this->anim_buf;
|
||||
Colour *dst = (Colour *)_screen.dst_ptr;
|
||||
|
||||
/* Let's walk the anim buffer and try to find the pixels */
|
||||
@@ -502,8 +518,8 @@ void Blitter_32bppAnim::PaletteAnimate(const Palette &palette)
|
||||
const int anim_pitch_offset = this->anim_buf_pitch - width;
|
||||
for (int y = this->anim_buf_height; y != 0 ; y--) {
|
||||
for (int x = width; x != 0 ; x--) {
|
||||
uint16 value = *anim;
|
||||
uint8 colour = GB(value, 0, 8);
|
||||
uint16_t value = *anim;
|
||||
uint8_t colour = GB(value, 0, 8);
|
||||
if (colour >= PALETTE_ANIM_START) {
|
||||
/* Update this pixel */
|
||||
*dst = this->AdjustBrightness(LookupColourInPalette(colour), GB(value, 8, 8));
|
||||
@@ -533,9 +549,9 @@ void Blitter_32bppAnim::PostResize()
|
||||
this->anim_buf_width = _screen.width;
|
||||
this->anim_buf_height = _screen.height;
|
||||
this->anim_buf_pitch = (_screen.width + 7) & ~7;
|
||||
this->anim_alloc = CallocT<uint16>(this->anim_buf_pitch * this->anim_buf_height + 8);
|
||||
this->anim_alloc = CallocT<uint16_t>(this->anim_buf_pitch * this->anim_buf_height + 8);
|
||||
|
||||
/* align buffer to next 16 byte boundary */
|
||||
this->anim_buf = reinterpret_cast<uint16 *>((reinterpret_cast<uintptr_t>(this->anim_alloc) + 0xF) & (~0xF));
|
||||
this->anim_buf = reinterpret_cast<uint16_t *>((reinterpret_cast<uintptr_t>(this->anim_alloc) + 0xF) & (~0xF));
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user