Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MakerBot plugin #5

Merged
merged 91 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from 81 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
df9b0b5
Add CTRE as dep
jellespijker Oct 16, 2023
03b4512
Add IO utilities for file reading
jellespijker Oct 15, 2023
0a546e7
fix incorrect path io header
jellespijker Oct 16, 2023
4a338f1
Add GCode parsing functionality
jellespijker Oct 16, 2023
cc1eba9
Applied clang-format.
jellespijker Oct 16, 2023
d9a9f28
Refactor G-Code AST classes and added translation functionality
jellespijker Oct 16, 2023
3e43412
Applied clang-format.
jellespijker Oct 16, 2023
a8e0443
Modify code for better traversal of GCode AST
jellespijker Oct 16, 2023
98e0afd
Applied clang-format.
jellespijker Oct 16, 2023
2d9dc21
Revert "Applied clang-format."
jellespijker Oct 17, 2023
01c2c33
Revert "Modify code for better traversal of GCode AST"
jellespijker Oct 17, 2023
1f7a92a
Introduce a universal proto language
jellespijker Oct 17, 2023
d021414
Applied clang-format.
jellespijker Oct 17, 2023
8d36970
improve Gcode parsing
jellespijker Oct 17, 2023
15eb0de
Rename file and enhance parse error messages
jellespijker Oct 18, 2023
94eb3f1
Combine g1 and g2 into one command
casperlamboo Oct 24, 2023
2ddc6c4
Add delay and comment commands
casperlamboo Oct 24, 2023
3681de5
Add ranges dependency
casperlamboo Oct 24, 2023
13dda18
Implement basic translation from gcode ast to command list
casperlamboo Oct 24, 2023
6ebc114
Applied clang-format.
casperlamboo Oct 24, 2023
2e8244e
Fix G92 command
casperlamboo Oct 25, 2023
93a2660
Allow for relative positioning in move command
casperlamboo Oct 25, 2023
19ab560
Use string to locally copy string views
casperlamboo Oct 25, 2023
446baef
Fix parsing floats on mac
casperlamboo Oct 25, 2023
04b9cc6
Applied clang-format.
casperlamboo Oct 25, 2023
8dc6295
Disable comments
casperlamboo Oct 25, 2023
8d1307a
Merge remote-tracking branch 'origin/CURA-10561_regex_gcode_parser' i…
casperlamboo Oct 25, 2023
4a0aaef
Also write to json in example code
casperlamboo Oct 25, 2023
d51d1dc
Fix write file ultilty
casperlamboo Oct 25, 2023
574de0e
Applied clang-format.
casperlamboo Oct 25, 2023
55e4da0
Add tags to move commands
casperlamboo Oct 25, 2023
394c803
Applied clang-format.
casperlamboo Oct 25, 2023
71d55e2
Add support io support to pyDulcificum
jellespijker Oct 26, 2023
e1f75c4
Add translation functionality to pyDulcificum
jellespijker Oct 26, 2023
2dc556a
Add translation functionality to pyDulcificum
jellespijker Oct 26, 2023
4e93fde
Add nlohmann/json_fwd and string includes to dulcificum.h
jellespijker Oct 26, 2023
e9989f7
Build CPython shared when compiling with msvc
jellespijker Oct 26, 2023
590d833
Fix function decleration
jellespijker Oct 26, 2023
758571c
Package the Python module and library
jellespijker Oct 26, 2023
9113cb6
Refactor testing condition in conanfile.py
jellespijker Oct 27, 2023
9852b72
Add LayerChange command
casperlamboo Oct 27, 2023
8efce15
Applied clang-format.
casperlamboo Oct 27, 2023
2ac9973
Map layer change to comment
casperlamboo Oct 27, 2023
01f73f3
Merge remote-tracking branch 'origin/CURA-10561_regex_gcode_parser' i…
casperlamboo Oct 27, 2023
ad56e31
Print each line on seperate line
casperlamboo Oct 27, 2023
b4444b6
Applied clang-format.
casperlamboo Oct 27, 2023
5838f06
Fix printing gcode on different lines
casperlamboo Oct 27, 2023
ec1b28f
Merge remote-tracking branch 'origin/CURA-10561_regex_gcode_parser' i…
casperlamboo Oct 27, 2023
39291fe
Applied clang-format.
casperlamboo Oct 27, 2023
235b548
Fix printing gcode on different lines
casperlamboo Oct 27, 2023
00067e2
Applied clang-format.
casperlamboo Oct 27, 2023
d6eeab6
Fix editablemode
casperlamboo Oct 27, 2023
93827ed
Multiple package fixes
jellespijker Oct 27, 2023
5b2c9b1
fix typo
jellespijker Oct 27, 2023
809f42e
Fixed multiple compiler clang-tidy warnings
jellespijker Oct 28, 2023
16e6cd7
Refactor gcode_to_command.cpp for modular code
jellespijker Oct 28, 2023
47874f4
Move declaration of VisitCommand out of cpp
jellespijker Oct 28, 2023
9dc5c92
Fixed GCC-13 compiler crash
jellespijker Oct 28, 2023
158f75c
Allow for shared libs on Windows
jellespijker Oct 28, 2023
2197857
No `constexpr`
jellespijker Oct 28, 2023
b2e8a6e
No need to link directly with cpython
jellespijker Oct 28, 2023
6afeaea
Also run workflow when pyDulcificum is changed
jellespijker Oct 28, 2023
8e057bd
Return protopath in toCommand fn
casperlamboo Oct 29, 2023
01a5f9a
Add support for `T`, `Layer` and `Comment` commands in to proto
casperlamboo Oct 29, 2023
3070271
Revert "Allow for shared libs on Windows"
jellespijker Oct 29, 2023
3711f75
Merge remote-tracking branch 'origin/CURA-10561_regex_gcode_parser' i…
casperlamboo Oct 29, 2023
3c52e38
package pyd
jellespijker Oct 29, 2023
12df764
Use correct unit
casperlamboo Oct 29, 2023
a9c9136
Merge remote-tracking branch 'origin/CURA-10561_regex_gcode_parser' i…
casperlamboo Oct 29, 2023
84c77ab
Applied clang-format.
casperlamboo Oct 29, 2023
1c32f66
use cpp comment
jellespijker Oct 29, 2023
a8328c0
Set temperature commands in integers
casperlamboo Oct 29, 2023
079c573
Applied clang-format.
casperlamboo Oct 29, 2023
8b0921a
Offset negative raft layer index
jellespijker Oct 29, 2023
01648f8
Applied clang-format.
jellespijker Oct 29, 2023
d7182d8
Set temperature of correct target
casperlamboo Oct 29, 2023
e70fe1d
Update value extraction from optional command parameters
jellespijker Oct 29, 2023
45001ab
Add initial temperature to protopath
casperlamboo Oct 29, 2023
1ff1164
Merge remote-tracking branch 'origin/CURA-10561_regex_gcode_parser' i…
casperlamboo Oct 29, 2023
f73ad27
Refactor command naming for clearer code readability
jellespijker Oct 29, 2023
048b151
Set temperature of correct tool
casperlamboo Oct 29, 2023
ed12e00
Wait for temperature
casperlamboo Oct 29, 2023
3c9e886
Parsing the P index for Fan
jellespijker Oct 30, 2023
a830455
Allow for P parameter for M106 and M107
jellespijker Oct 30, 2023
76c942c
Applied clang-format.
jellespijker Oct 30, 2023
99b1842
Use rel E and store origins
jellespijker Oct 31, 2023
480a555
Applied clang-format.
jellespijker Oct 31, 2023
3f55bf0
Fix bug where temp was updating wrong extruder
casperlamboo Oct 31, 2023
8ddd06f
Get tool from command
casperlamboo Oct 31, 2023
d755576
Merge remote-tracking branch 'origin/CURA-10561_regex_gcode_parser' i…
casperlamboo Oct 31, 2023
46917cf
Fix error
casperlamboo Oct 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/conan-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ on:
- 'test_package/**'
- 'conanfile.py'
- 'CMakeLists.txt'
- 'pyDulcificum/**'
- '.github/workflows/conan-package.yml'
- '.github/worflows/requirements-conan-package.txt'
branches:
Expand Down
14 changes: 12 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,28 @@ message(STATUS "Configuring Dulcificum version: ${DULCIFICUM_VERSION}")
find_package(nlohmann_json REQUIRED)
find_package(spdlog REQUIRED)
find_package(range-v3 REQUIRED)
find_package(ctre REQUIRED)

# --- Setup the shared C++ mgjtp library ---
set(DULCIFICUM_SRC
src/command_types.cpp
src/gcode/ast/ast.cpp
src/gcode/ast/entries.cpp
src/gcode/parse.cpp

src/miracle_jtp/mgjtp_command_to_json.cpp
src/miracle_jtp/mgjtp_json_to_command.cpp

src/gcode/gcode_to_command.cpp

src/utils/io.cpp
src/utils/svtod.cpp
src/command_types.cpp
)
add_library(dulcificum ${DULCIFICUM_SRC})
target_link_libraries(dulcificum
PUBLIC
nlohmann_json::nlohmann_json
PRIVATE
ctre::ctre
range-v3::range-v3
spdlog::spdlog)

Expand Down
2 changes: 1 addition & 1 deletion apps/cmdline.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ constexpr std::string_view USAGE = R"({0}.
Dulcificum changes the flavor, or dialect, of 3d printer commands

Usage:
translator [--quiet | --verbose] --input=FLAVOR INPUT --output=FLAVOR OUPUT
translator [--quiet | --verbose] --input=FLAVOR INPUT --output=FLAVOR OUTPUT
translator (-h | --help)
translator --version

Expand Down
23 changes: 21 additions & 2 deletions apps/translator_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,34 @@
#include <spdlog/spdlog.h>

#include <docopt/docopt.h>
#include <dulcificum/gcode/parse.h>
#include <dulcificum/miracle_jtp/mgjtp_command_to_json.h>
#include <dulcificum/gcode/gcode_to_command.h>
#include <dulcificum/utils/io.h>
#include <dulcificum.h>
#include <map>

#include <nlohmann/json.hpp>

template<typename... Ts>
struct Overload : Ts...
{
using Ts::operator()...;
};
template<class... Ts>
Overload(Ts...) -> Overload<Ts...>;
casperlamboo marked this conversation as resolved.
Show resolved Hide resolved

int main(int argc, const char** argv)
{
constexpr bool show_help = true;
const std::map<std::string, docopt::value> args
= docopt::docopt(fmt::format(apps::cmdline::USAGE, apps::cmdline::NAME), { argv + 1, argv + argc }, show_help, apps::cmdline::VERSION_ID);

if (args.contains("--quiet"))
if (args.at("--quiet").asBool())
{
spdlog::set_level(spdlog::level::err);
}
else if (args.contains("--verbose"))
else if (args.at("--verbose").asBool())
{
spdlog::set_level(spdlog::level::debug);
}
Expand All @@ -24,4 +39,8 @@ int main(int argc, const char** argv)
spdlog::set_level(spdlog::level::info);
}
spdlog::info("Tasting the menu");

auto input{ dulcificum::utils::readFile(args.at("INPUT").asString()).value() };
auto translated = dulcificum::GCode2Miracle_JTP(input);
dulcificum::utils::writeFile(args.at("OUTPUT").asString(), translated);
}
36 changes: 30 additions & 6 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class DulcificumConan(ConanFile):
"shared": False,
"fPIC": True,
"enable_extensive_warnings": False,
"with_apps": True,
"with_apps": False,
"with_python_bindings": True,
}

Expand All @@ -57,6 +57,12 @@ def _compilers_minimum_version(self):
"visual_studio": "17",
}

@property
def _run_tests(self):
if self.settings.compiler == "apple-clang" and Version(self.settings.compiler.version) <= Version("14"):
return False
return not self.conf.get("tools.build:skip_test", False, check_type = bool)

def export_sources(self):
copy(self, "CMakeLists.txt", self.recipe_folder, self.export_sources_folder)
copy(self, "*", os.path.join(self.recipe_folder, "src"), os.path.join(self.export_sources_folder, "src"))
Expand All @@ -72,15 +78,25 @@ def config_options(self):
def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")
if self.options.with_python_bindings:
self.options["cpython"].shared = True

def layout(self):
cmake_layout(self)
self.cpp.package.libs = ["dulcificum"]

self.cpp.build.bin = ["translator"]
self.cpp.build.bindirs = ["apps"]

self.cpp.package.lib = ["dulcificum", "pyDulcificum"]
self.cpp.package.libdirs = ["lib"]
self.cpp.package.bindirs = ["bin"]

def requirements(self):
self.requires("nlohmann_json/3.11.2", transitive_headers = True)
self.requires("range-v3/0.12.0")
self.requires("spdlog/1.10.0")
self.requires("ctre/3.7.2")
self.requires("range-v3/0.12.0")
casperlamboo marked this conversation as resolved.
Show resolved Hide resolved
if self.options.with_apps:
self.requires("docopt.cpp/0.6.3")
if self.options.with_python_bindings:
Expand All @@ -89,7 +105,7 @@ def requirements(self):

def build_requirements(self):
self.test_requires("standardprojectsettings/[>=0.1.0]@ultimaker/stable")
if not self.conf.get("tools.build:skip_test", False, check_type = bool):
if self._run_tests:
self.test_requires("gtest/[>=1.12.1]")

def validate(self):
Expand All @@ -107,7 +123,7 @@ def validate(self):

def generate(self):
tc = CMakeToolchain(self)
tc.variables["ENABLE_TESTS"] = not self.conf.get("tools.build:skip_test", False, check_type = bool)
tc.variables["ENABLE_TESTS"] = self._run_tests
tc.variables["EXTENSIVE_WARNINGS"] = self.options.enable_extensive_warnings
tc.variables["DULCIFICUM_VERSION"] = self.version

Expand All @@ -117,7 +133,7 @@ def generate(self):

tc.variables["WITH_PYTHON_BINDINGS"] = self.options.with_python_bindings
if self.options.with_python_bindings:
tc.variables["Python_EXECUTABLE"] = self.deps_user_info["cpython"].python.replace("\\", "/")
tc.variables["PYTHON_EXECUTABLE"] = self.deps_user_info["cpython"].python.replace("\\", "/")
tc.variables["Python_USE_STATIC_LIBS"] = not self.options["cpython"].shared
tc.variables["Python_ROOT_DIR"] = self.deps_cpp_info["cpython"].rootpath.replace("\\", "/")
tc.variables["Python_FIND_FRAMEWORK"] = "NEVER"
Expand All @@ -143,7 +159,7 @@ def generate(self):
copy(self, "*.dll", dep.cpp_info.libdirs[0], self.build_folder)
if len(dep.cpp_info.bindirs) > 0:
copy(self, "*.dll", dep.cpp_info.bindirs[0], self.build_folder)
if not self.conf.get("tools.build:skip_test", False, check_type = bool):
if self._run_tests:
test_path = os.path.join(self.build_folder, "tests")
if not os.path.exists(test_path):
mkdir(self, test_path)
Expand All @@ -160,5 +176,13 @@ def build(self):

def package(self):
copy(self, pattern="LICENSE", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder)
copy(self, "translator*", src = os.path.join(self.build_folder, "apps"), dst = os.path.join(self.package_folder, "bin"), keep_path = False)
copy(self, "*.pyd", src = os.path.join(self.build_folder, "pyDulcificum"), dst = os.path.join(self.package_folder, "lib", "pyDulcificum"), keep_path = False)
packager = AutoPackager(self)
packager.run()

def package_info(self):
if self.in_local_cache:
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.package_folder, "lib", "pyDulcificum"))
else:
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.build_folder, "pyDulcificum"))
33 changes: 32 additions & 1 deletion include/dulcificum.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,41 @@
#ifndef DULCIFICUM_INCLUDE_DULCIFICUM_H
#define DULCIFICUM_INCLUDE_DULCIFICUM_H

#include <nlohmann/json_fwd.hpp>
#include <string>
#ifndef DULCIFICUM_VERSION
#define DULCIFICUM_VERSION "0.1.0"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ cppcoreguidelines-macro-usage ⚠️
macro DULCIFICUM_VERSION used to declare a constant; consider using a constexpr constant

#endif

// TODO: this will be the main API
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <range/v3/to_container.hpp>
#include <range/v3/view/c_str.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/view/transform.hpp>

#include <dulcificum/gcode/gcode_to_command.h>
#include <dulcificum/gcode/parse.h>
#include <dulcificum/miracle_jtp/mgjtp_command_to_json.h>

namespace dulcificum
{

[[nodiscard]] std::string GCode2Miracle_JTP(const std::string& content)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ readability-identifier-naming ⚠️
invalid case style for function GCode2Miracle_JTP

Suggested change
[[nodiscard]] std::string GCode2Miracle_JTP(const std::string& content)
[[nodiscard]] std::string gCode2MiracleJtp(const std::string& content)

{
auto gcode_ast = dulcificum::gcode::parse(content);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are errors/warnings reported ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not use auto when the type is not explicit

auto command_list = dulcificum::gcode::toCommand(gcode_ast);
auto commands = command_list
| ranges::views::transform(
[](const auto& command)
{
return dulcificum::miracle_jtp::toJson(*command).dump();
})
| ranges::views::join(ranges::views::c_str(",\n")) | ranges::to<std::string>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this could be splitted a bit for easier readability ?

Copy link
Contributor Author

@casperlamboo casperlamboo Nov 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don;t really like the formatting here (caused by the auto-formatter) but I do think ranges are very readable

    auto commands 
                 = command_list    // original command ist
                  | ranges::views::transform([](const auto& command) { 
                      return dulcificum::miracle_jtp::toJson(*command).dump(); 
                   })       // transform each string to json
                  | ranges::views::join(ranges::views::c_str(",\n"))    // intersperse the commands with commas and line break
                  | ranges::to<std::string>();    // convert the range to a string

I think this is partitioned/split into readable chunks way more then a for loop

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When written like that, yeah it feels much better.

return fmt::format("[\n{}\n]", commands);
casperlamboo marked this conversation as resolved.
Show resolved Hide resolved
}


} // namespace dulcificum

#endif // DULCIFICUM_INCLUDE_DULCIFICUM_H
72 changes: 42 additions & 30 deletions include/dulcificum/command_types.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef DULCIFICUM_COMMAND_TYPES_H
#define DULCIFICUM_COMMAND_TYPES_H
#ifndef INCLUDE_DULCIFICUM_COMMAND_TYPES_H
#define INCLUDE_DULCIFICUM_COMMAND_TYPES_H

#include <cmath>
#include <memory>
Expand All @@ -17,16 +17,17 @@ namespace botcmd

enum class CommandType
{
kInvalid,
kMove, // most commands are move commands
kActiveFanEnable, // look at m_fan_state
kActiveFanDuty, // look at m_fan_speed
kSetTemperature, // change temperature for active tool
kChangeTool, // change active tool
kComment, // do nothing, only emit comments
kDelay, // delay - command to wait for event
kWaitForTemperature, // firmware delays until temp reached
kPause, // Command to allow for user defined pause.
Invalid,
Move, // most commands are move commands
ActiveFanEnable, // look at m_fan_state
ActiveFanDuty, // look at m_fan_speed
SetTemperature, // change temperature for active tool
ChangeTool, // change active tool
Comment, // do nothing, only emit comments
Delay, // delay - command to wait for event
LayerChange, // layer - denoting a layer is changed
WaitForTemperature, // firmware delays until temp reached
Pause, // Command to allow for user defined pause.
};

enum class Tag
Expand All @@ -38,6 +39,7 @@ enum class Tag
QuickToggle,
Raft,
Restart,
Retract,
Roof,
Support,
Sparse,
Expand All @@ -50,7 +52,7 @@ struct Command
{
Command() = delete;

constexpr explicit Command(CommandType type) noexcept
explicit Command(CommandType type) noexcept
: type{ type }
{
}
Expand All @@ -65,7 +67,7 @@ using CommandList = std::vector<CommandPtr>;
struct Comment : public Command
{
Comment() noexcept
: Command(CommandType::kComment)
: Command(CommandType::Comment)
{
}

Expand All @@ -74,8 +76,8 @@ struct Comment : public Command

struct Move : public Command
{
constexpr Move() noexcept
: Command(CommandType::kMove)
Move() noexcept
: Command(CommandType::Move)
{
}

Expand All @@ -86,8 +88,8 @@ struct Move : public Command

struct FanDuty : public Command
{
constexpr FanDuty() noexcept
: Command(CommandType::kActiveFanDuty)
FanDuty() noexcept
: Command(CommandType::ActiveFanDuty)
{
}

Expand All @@ -97,8 +99,8 @@ struct FanDuty : public Command

struct FanToggle : public Command
{
constexpr FanToggle() noexcept
: Command(CommandType::kActiveFanEnable)
FanToggle() noexcept
: Command(CommandType::ActiveFanEnable)
{
}

Expand All @@ -108,8 +110,8 @@ struct FanToggle : public Command

struct SetTemperature : public Command
{
constexpr SetTemperature() noexcept
: Command(CommandType::kSetTemperature)
SetTemperature() noexcept
: Command(CommandType::SetTemperature)
{
}

Expand All @@ -119,8 +121,8 @@ struct SetTemperature : public Command

struct WaitForTemperature : public Command
{
constexpr WaitForTemperature() noexcept
: Command(CommandType::kWaitForTemperature)
WaitForTemperature() noexcept
: Command(CommandType::WaitForTemperature)
{
}

Expand All @@ -129,28 +131,38 @@ struct WaitForTemperature : public Command

struct ChangeTool : public Command
{
constexpr ChangeTool() noexcept
: Command(CommandType::kChangeTool)
ChangeTool() noexcept
: Command(CommandType::ChangeTool)
{
}

ExtruderIndex index{ 0 };
ParamPoint position{ NAN, NAN, NAN, NAN, NAN };
ParamPoint position{ NAN, NAN, NAN, NAN, NAN }; // Badman
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


struct Delay : public Command
{
constexpr Delay() noexcept
: Command(CommandType::kDelay)
Delay() noexcept
: Command(CommandType::Delay)
{
}

double seconds{ 0.0 };
};

struct LayerChange : public Command
{
LayerChange() noexcept
: Command(CommandType::LayerChange)
{
}

int64_t layer{ 0 };
};

CommandPtr spawnCommandPtr(const CommandType& type) noexcept;

} // namespace botcmd
} // namespace dulcificum

#endif // DULCIFICUM_COMMAND_TYPES_H
#endif // INCLUDE_DULCIFICUM_COMMAND_TYPES_H
Loading
Loading