Update to 14.0-beta1

This commit is contained in:
dP
2024-02-04 02:18:17 +05:30
parent 79037e2c65
commit 33ef333b57
1325 changed files with 138461 additions and 70983 deletions
+5 -1
View File
@@ -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)
+1 -1
View File
@@ -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.
+3
View File
@@ -0,0 +1,3 @@
add_files(
catch.hpp
)
+23
View File
@@ -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.
+17976
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -1,5 +1,9 @@
add_files(
chrono.h
core.h
format.h
format-inl.h
ostream.h
ranges.h
std.h
)
+1 -1
View File
@@ -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
+2240
View File
File diff suppressed because it is too large Load Diff
+2192 -1350
View File
File diff suppressed because it is too large Load Diff
+1283 -2411
View File
File diff suppressed because it is too large Load Diff
+3560 -2986
View File
File diff suppressed because it is too large Load Diff
+245
View File
@@ -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_
+738
View File
@@ -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_
+537
View File
@@ -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_
+5
View File
@@ -0,0 +1,5 @@
add_files(
scriptrun.cpp
scriptrun.h
CONDITION ICU_i18n_FOUND
)
+46
View File
@@ -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.
+208
View File
@@ -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
+159
View File
@@ -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
+29 -29
View File
@@ -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));
}
}
+24 -5
View File
@@ -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 */
+63
View File
@@ -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.
+295
View File
@@ -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
View File
@@ -0,0 +1,6 @@
add_files(
monocypher-ed25519.cpp
monocypher-ed25519.h
monocypher.cpp
monocypher.h
)
+167
View File
@@ -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.
+164
View File
@@ -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
View File
@@ -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
View File
@@ -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
File diff suppressed because it is too large Load Diff
+321
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
add_files(
json.hpp
)
+21
View File
@@ -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.
+24765
View File
File diff suppressed because it is too large Load Diff
+117 -66
View File
@@ -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
+24 -3
View File
@@ -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
+1 -1
View File
@@ -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
)
+20
View File
@@ -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 */
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+4 -8
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
-7
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+5 -6
View File
@@ -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);
}
+2 -2
View File
@@ -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
View File
@@ -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);
+6 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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. */
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+1 -2
View File
@@ -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"
+58 -35
View File
@@ -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();
}
}
+2 -2
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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, &nothing_to_do);
} else {
+6 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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 ||
+10
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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