Reimplementing save/load file

This commit is contained in:
Yousef Khadadeh 2026-01-01 22:46:02 +03:00
parent 260288a1b0
commit 9913eb6c8e
37 changed files with 437 additions and 350 deletions

View file

@ -36,7 +36,6 @@ set(sources "src/main.cpp"
"src/GridManager.cpp"
"src/WorldGrid.cpp"
"src/TimePoint.cpp"
"src/ConnectionManager.cpp"
"src/InputManager.cpp"
"src/UndoManager.cpp"
"src/CanvasTheme.cpp"

View file

@ -2,6 +2,8 @@
#include <cereal/types/string.hpp>
#include "../World.hpp"
#include "../ScaleUpCanvas.hpp"
#include "BookmarkManager.hpp"
#include "../World.hpp"
using namespace NetworkingObjects;
@ -104,3 +106,38 @@ void BookmarkListItem::write_constructor_data(const NetObjTemporaryPtr<BookmarkL
a(*o->bookmarkData);
o->nameData.write_create_message(a);
}
void BookmarkListItem::save_file(cereal::PortableBinaryOutputArchive& a) const {
a(*nameData);
a(static_cast<bool>(folderData));
if(folderData) {
a(folderData->folderList->size());
for(auto& item : *folderData->folderList)
item.obj->save_file(a);
}
else
a(*bookmarkData);
}
void BookmarkListItem::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, BookmarkManager& bMan) {
nameData = bMan.world.netObjMan.make_obj<NameData>();
a(*nameData);
bool isFolder;
a(isFolder);
if(isFolder) {
folderData = std::make_unique<BookmarkFolderData>();
folderData->folderList = bMan.world.netObjMan.make_obj<NetworkingObjects::NetObjOrderedList<BookmarkListItem>>();
uint32_t folderSize;
a(folderSize);
for(uint32_t i = 0; i < folderSize; i++) {
BookmarkListItem* item = new BookmarkListItem;
item->load_file(a, version, bMan);
folderData->folderList->push_back_and_send_create(folderData->folderList, item);
}
}
else {
bookmarkData = std::make_unique<BookmarkData>();
a(*bookmarkData);
}
}

View file

@ -4,6 +4,9 @@
#include <Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp>
#include <string>
#include "../CoordSpaceHelper.hpp"
#include <Helpers/VersionNumber.hpp>
class BookmarkManager;
struct BookmarkData {
CoordSpaceHelper coords;
@ -27,7 +30,9 @@ class BookmarkListItem {
static void register_class(World& w);
void reassign_netobj_ids_call();
void scale_up(const WorldScalar& scaleUpAmount);
void save_file(cereal::PortableBinaryOutputArchive& a) const;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, BookmarkManager& bMan);
void set_name(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, const std::string& newName);
private:
struct BookmarkFolderData {

View file

@ -9,12 +9,8 @@ BookmarkManager::BookmarkManager(World& w):
world(w)
{}
void BookmarkManager::init() {
// NOTE: Should find a way for bookmarks added from the network to take into account the client's canvasScale
// Have the canvasScale variable come with the ClientData object, and the grid scale commands can be part of
// the client data class
if(world.netObjMan.is_server())
bookmarkListRoot = world.netObjMan.make_obj_from_ptr<BookmarkListItem>(new BookmarkListItem(world.netObjMan, "ROOT", true, {}));
void BookmarkManager::server_init_no_file() {
bookmarkListRoot = world.netObjMan.make_obj_from_ptr<BookmarkListItem>(new BookmarkListItem(world.netObjMan, "ROOT", true, {}));
}
void BookmarkManager::refresh_gui_data() {
@ -200,3 +196,13 @@ NetworkingObjects::NetObjOrderedListIterator<BookmarkListItem> BookmarkManager::
void BookmarkManager::scale_up(const WorldScalar& scaleUpAmount) {
bookmarkListRoot->scale_up(scaleUpAmount);
}
void BookmarkManager::save_file(cereal::PortableBinaryOutputArchive& a) const {
bookmarkListRoot->save_file(a);
}
void BookmarkManager::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) {
bookmarkListRoot = world.netObjMan.make_obj_from_ptr<BookmarkListItem>(new BookmarkListItem());
bookmarkListRoot->load_file(a, version, *this);
}

View file

@ -4,22 +4,19 @@
#include <Helpers/NetworkingObjects/NetObjOrderedList.hpp>
#include "../GUIStuff/Elements/TreeListing.hpp"
#include "BookmarkListItem.hpp"
#include <Helpers/VersionNumber.hpp>
class World;
class BookmarkManager {
public:
BookmarkManager(World& w);
void init();
void server_init_no_file();
void scale_up(const WorldScalar& scaleUpAmount);
void setup_list_gui(const std::string& id);
void refresh_gui_data();
template <typename Archive> void save(Archive& a) const {
}
template <typename Archive> void load(Archive& a) {
}
void save_file(cereal::PortableBinaryOutputArchive& a) const;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version);
NetworkingObjects::NetObjOwnerPtr<BookmarkListItem> bookmarkListRoot;
private:
@ -30,5 +27,7 @@ class BookmarkManager {
std::string nameToEdit;
std::string nameForNew;
friend class BookmarkListItem;
World& world;
};

View file

@ -43,3 +43,15 @@ void CanvasComponentAllocator::register_class(World& world) {
}
});
}
void CanvasComponentAllocator::save_file(cereal::PortableBinaryOutputArchive& a) const {
a(comp->get_type());
comp->save_file(a);
}
void CanvasComponentAllocator::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) {
CanvasComponentType t;
a(t);
comp = std::unique_ptr<CanvasComponent>(CanvasComponent::allocate_comp(t));
comp->load_file(a, version);
}

View file

@ -3,6 +3,7 @@
#include "CanvasComponentType.hpp"
#include <Helpers/NetworkingObjects/NetObjTemporaryPtr.hpp>
#include <Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp>
#include <Helpers/VersionNumber.hpp>
class World;
class CanvasComponent;
@ -13,4 +14,6 @@ class CanvasComponentAllocator {
CanvasComponentAllocator(CanvasComponentType typeToAllocate);
std::unique_ptr<CanvasComponent> comp;
static void register_class(World& world);
void save_file(cereal::PortableBinaryOutputArchive& a) const;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version);
};

View file

@ -6,6 +6,7 @@
#include "CanvasComponent.hpp"
#include <Helpers/NetworkingObjects/DelayUpdateSerializedClassManager.hpp>
#include "../ScaleUpCanvas.hpp"
#include "Helpers/NetworkingObjects/NetObjManager.hpp"
using namespace NetworkingObjects;
@ -58,12 +59,14 @@ void CanvasComponentContainer::write_constructor_func(const NetworkingObjects::N
void CanvasComponentContainer::save_file(cereal::PortableBinaryOutputArchive& a) const {
a(coords);
get_comp().save_file(a);
compAllocator->save_file(a);
}
void CanvasComponentContainer::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) {
void CanvasComponentContainer::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, NetObjManager& objMan) {
a(coords);
get_comp().load_file(a, version);
compAllocator = objMan.make_obj_direct<CanvasComponentAllocator>();
compAllocator->load_file(a, version);
compAllocator->comp->compContainer = this;
}
void CanvasComponentContainer::draw(SkCanvas* canvas, const DrawData& drawData) const {

View file

@ -37,7 +37,7 @@ class CanvasComponentContainer {
static void register_class(World& w);
std::shared_ptr<CopyData> get_data_copy() const;
void save_file(cereal::PortableBinaryOutputArchive& a) const;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version);
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, NetworkingObjects::NetObjManager& objMan);
CanvasComponent& get_comp() const;
SCollision::AABB<WorldScalar> get_world_bounds() const;
void draw(SkCanvas* canvas, const DrawData& drawData) const;

View file

@ -11,11 +11,9 @@ CanvasTheme::CanvasTheme(World& w):
world(w)
{}
void CanvasTheme::init() {
if(world.netObjMan.is_server()) {
backColor = world.netObjMan.make_obj_direct<BackColor>(world.main.defaultCanvasBackgroundColor);
set_tool_front_color(world.drawProg);
}
void CanvasTheme::server_init_no_file() {
backColor = world.netObjMan.make_obj_direct<BackColor>(world.main.defaultCanvasBackgroundColor);
set_tool_front_color(world.drawProg);
}
SkColor4f CanvasTheme::get_back_color() const {
@ -63,3 +61,24 @@ void CanvasTheme::read_create_message(cereal::PortableBinaryInputArchive& a) {
void CanvasTheme::write_create_message(cereal::PortableBinaryOutputArchive& a) const {
backColor.write_create_message(a);
}
void CanvasTheme::save_file(cereal::PortableBinaryOutputArchive& a) const {
a(convert_vec3<Vector3f>(get_back_color()));
}
void CanvasTheme::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) {
backColor = world.netObjMan.make_obj_direct<BackColor>(world.main.defaultCanvasBackgroundColor);
set_tool_front_color(world.drawProg);
if(version < VersionNumber(0, 1, 0))
set_back_color(DEFAULT_CANVAS_BACKGROUND_COLOR);
else {
Vector3f canvasBackColor;
a(canvasBackColor);
const Vector3f OLD_DEFAULT_CANVAS_BACKGROUND_COLOR{0.12f, 0.12f, 0.12f};
if(version < VersionNumber(0, 3, 0) && canvasBackColor == OLD_DEFAULT_CANVAS_BACKGROUND_COLOR)
set_back_color(DEFAULT_CANVAS_BACKGROUND_COLOR);
else
set_back_color(canvasBackColor);
}
}

View file

@ -4,6 +4,7 @@
#include <Helpers/ConvertVec.hpp>
#include <Helpers/NetworkingObjects/NetObjOwnerPtr.hpp>
#include <Helpers/Serializers.hpp>
#include <Helpers/VersionNumber.hpp>
class DrawingProgram;
class World;
@ -11,13 +12,15 @@ class World;
class CanvasTheme {
public:
CanvasTheme(World& w);
void init();
void server_init_no_file();
SkColor4f get_back_color() const;
const SkColor4f& get_tool_front_color() const;
void set_back_color(const Vector3f& newBackColor);
void register_class();
void read_create_message(cereal::PortableBinaryInputArchive& a);
void write_create_message(cereal::PortableBinaryOutputArchive& a) const;
void save_file(cereal::PortableBinaryOutputArchive& a) const;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version);
private:
void set_tool_front_color(DrawingProgram& drawP);
struct BackColor {

View file

@ -1,40 +0,0 @@
#include "ConnectionManager.hpp"
#include "Helpers/Networking/NetLibrary.hpp"
#include "CommandList.hpp"
#include <chrono>
#include "World.hpp"
#include <Helpers/Logger.hpp>
void ConnectionManager::connect_p2p(World& initWorld, const std::string& serverFullID) {
client = std::make_shared<NetClient>(serverFullID);
lastKeepAliveTime = std::chrono::steady_clock::now();
NetLibrary::register_client(client);
initWorld.netObjMan.set_client(client, SERVER_UPDATE_NETWORK_OBJECT, SERVER_UPDATE_MANY_NETWORK_OBJECTS);
}
void ConnectionManager::update() {
if(client) {
client->update();
if(std::chrono::steady_clock::now() - lastKeepAliveTime > std::chrono::seconds(2)) {
client->send_items_to_server(UNRELIABLE_COMMAND_CHANNEL, SERVER_KEEP_ALIVE);
lastKeepAliveTime = std::chrono::steady_clock::now();
}
}
}
void ConnectionManager::client_add_recv_callback(uint32_t commandID, const NetClientRecvCallback &callback) {
if(client)
client->add_recv_callback(commandID, callback);
}
bool ConnectionManager::is_client_disconnected() {
return client && client->is_disconnected();
}
bool ConnectionManager::client_exists() {
return client != nullptr;
}
NetLibrary::DownloadProgress ConnectionManager::client_get_resource_retrieval_progress() {
return client->get_progress_into_fragmented_message(RESOURCE_COMMAND_CHANNEL);
}

View file

@ -1,22 +0,0 @@
#pragma once
#include <Helpers/Networking/NetClient.hpp>
class World;
class ConnectionManager {
public:
void connect_p2p(World& initWorld, const std::string& serverFullID);
void update();
void client_add_recv_callback(uint32_t commandID, const NetClientRecvCallback &callback);
template <typename... Args> void client_send_items_to_server(const std::string& channel, Args&&... items) {
if(client)
client->send_items_to_server(channel, items...);
}
bool is_client_disconnected();
bool host_exists();
bool client_exists();
NetLibrary::DownloadProgress client_get_resource_retrieval_progress();
private:
std::shared_ptr<NetClient> client;
std::chrono::steady_clock::time_point lastKeepAliveTime;
};

View file

@ -169,3 +169,14 @@ void DrawCamera::update_main(World& w) {
if(c.inverseScale < WorldScalar(1))
w.scale_up_step();
}
void DrawCamera::save_file(cereal::PortableBinaryOutputArchive& a, const World& w) const {
a(c, w.main.window.size.cast<float>().eval());
}
void DrawCamera::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, World& w) {
CoordSpaceHelper coordsToJumpTo;
Vector2f windowSizeToJumpTo;
a(coordsToJumpTo, windowSizeToJumpTo);
smooth_move_to(w, coordsToJumpTo, windowSizeToJumpTo, true);
}

View file

@ -4,8 +4,7 @@
#include "SharedTypes.hpp"
#include <Helpers/SCollision.hpp>
#include "CoordSpaceHelper.hpp"
#include "include/core/SkMatrix.h"
#include <Helpers/VersionNumber.hpp>
using namespace Eigen;
@ -26,6 +25,9 @@ class DrawCamera {
void update_main(World& main);
void scale_up(World& w, const WorldScalar& scaleUpAmount);
void save_file(cereal::PortableBinaryOutputArchive& a, const World& w) const;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, World& w);
private:
struct SmoothMove {
CoordSpaceHelper start;

View file

@ -45,8 +45,8 @@ DrawingProgram::DrawingProgram(World& initWorld):
drawTool = DrawingProgramToolBase::allocate_tool_type(*this, DrawingProgramToolType::BRUSH);
}
void DrawingProgram::init() {
layerMan.init();
void DrawingProgram::server_init_no_file() {
layerMan.server_init_no_file();
}
void DrawingProgram::scale_up(const WorldScalar& scaleUpAmount) {
@ -83,7 +83,7 @@ void DrawingProgram::init_server_callbacks() {
}
void DrawingProgram::init_client_callbacks() {
world.con.client_add_recv_callback(CLIENT_TRANSFORM_MANY_COMPONENTS, [&](cereal::PortableBinaryInputArchive& message) {
world.netClient->add_recv_callback(CLIENT_TRANSFORM_MANY_COMPONENTS, [&](cereal::PortableBinaryInputArchive& message) {
std::vector<std::pair<NetworkingObjects::NetObjID, CoordSpaceHelper>> transforms;
message(transforms);
process_transform_message(transforms);
@ -111,7 +111,7 @@ void DrawingProgram::send_transforms_for(const std::vector<CanvasComponentContai
if(world.netObjMan.is_server())
world.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_TRANSFORM_MANY_COMPONENTS, transforms);
else
world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_TRANSFORM_MANY_COMPONENTS, transforms);
world.netClient->send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_TRANSFORM_MANY_COMPONENTS, transforms);
}
}
@ -538,29 +538,11 @@ void DrawingProgram::draw_drag_circle(SkCanvas* canvas, const Vector2f& sPos, co
}
void DrawingProgram::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) {
//uint64_t compCount;
//a(compCount);
//for(uint64_t i = 0; i < compCount; i++) {
// DrawComponentType t;
// a(t);
// auto newComp = DrawComponent::allocate_comp_type(t);
// a(newComp->id, newComp->coords);
// newComp->load_file(a, version);
// components.init_emplace_back(newComp);
//}
//parallel_loop_all_components([&](const auto& c){
// c->obj->commit_update(*this, false);
//});
//compCache.test_rebuild(components.client_list(), true);
layerMan.load_file(a, version);
}
void DrawingProgram::save_file(cereal::PortableBinaryOutputArchive& a) const {
//auto& cList = components->get_data();
//a((uint64_t)cList.size());
//for(size_t i = 0; i < cList.size(); i++) {
// a(cList[i]->obj->get_type(), cList[i]->obj->id, cList[i]->obj->coords);
// cList[i]->obj->save_file(a);
//}
layerMan.save_file(a);
}
void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {

View file

@ -23,7 +23,7 @@ class World;
class DrawingProgram {
public:
DrawingProgram(World& initWorld);
void init();
void server_init_no_file();
void toolbar_gui();
void tool_options_gui();
bool right_click_popup_gui(Vector2f popupPos);

View file

@ -1,6 +1,7 @@
#include "DrawingProgramLayer.hpp"
#include "DrawingProgramLayerManager.hpp"
#include "../DrawingProgram.hpp"
#include "../../World.hpp"
#include <Helpers/Parallel.hpp>
void DrawingProgramLayer::draw(SkCanvas* canvas, const DrawData& drawData) const {
@ -12,8 +13,10 @@ void DrawingProgramLayer::set_component_list_callbacks(DrawingProgramLayerListIt
auto insertCallback = [&](const CanvasComponentContainer::ObjInfoIterator& c) {
c->obj->objInfo = c;
c->obj->parentLayer = &layerListItem;
c->obj->commit_update(layerMan.drawP); // Run commit update on insert so that world bounds are calculated
layerMan.drawP.drawCache.add_component(&(*c));
if(layerMan.commitUpdateOnComponentInsert) {
c->obj->commit_update(layerMan.drawP); // Run commit update on insert so that world bounds are calculated
layerMan.drawP.drawCache.add_component(&(*c));
}
if(c->obj->get_comp().get_type() == CanvasComponentType::IMAGE)
layerMan.drawP.updateableComponents.emplace(&(*c));
};
@ -41,12 +44,6 @@ void DrawingProgramLayer::set_to_erase() {
eraseCallback(it);
}
void DrawingProgramLayer::commit_update_dont_invalidate_cache(DrawingProgramLayerManager& layerMan) const {
parallel_loop_container(*components, [&layerMan](auto& comp) {
comp.obj->commit_update_dont_invalidate_cache(layerMan.drawP);
});
}
void DrawingProgramLayer::get_flattened_component_list(std::vector<CanvasComponentContainer::ObjInfo*>& objList) const {
for(auto& p : *components)
objList.emplace_back(&p);
@ -56,3 +53,20 @@ void DrawingProgramLayer::scale_up(const WorldScalar& scaleUpAmount) {
for(auto& p : *components)
p.obj->scale_up(scaleUpAmount);
}
void DrawingProgramLayer::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, DrawingProgramLayerManager& layerMan) {
components = layerMan.drawP.world.netObjMan.make_obj<CanvasComponentContainer::NetList>();
uint32_t layerListSize;
a(layerListSize);
for(uint32_t i = 0; i < layerListSize; i++) {
CanvasComponentContainer* item = new CanvasComponentContainer();
item->load_file(a, version, layerMan.drawP.world.netObjMan);
components->push_back_and_send_create(components, item);
}
}
void DrawingProgramLayer::save_file(cereal::PortableBinaryOutputArchive& a) const {
a(components->size());
for(auto& comp : *components)
comp.obj->save_file(a);
}

View file

@ -10,12 +10,14 @@ class DrawingProgramLayer {
public:
void draw(SkCanvas* canvas, const DrawData& drawData) const;
void set_component_list_callbacks(DrawingProgramLayerListItem& layerListItem, DrawingProgramLayerManager& layerMan);
void commit_update_dont_invalidate_cache(DrawingProgramLayerManager& layerMan) const;
void get_flattened_component_list(std::vector<CanvasComponentContainer::ObjInfo*>& objList) const;
void set_to_erase();
void scale_up(const WorldScalar& scaleUpAmount);
CanvasComponentContainer::NetListOwnerPtr components;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, DrawingProgramLayerManager& layerMan);
void save_file(cereal::PortableBinaryOutputArchive& a) const;
private:
std::function<void(const CanvasComponentContainer::ObjInfoIterator& c)> eraseCallback;
};

View file

@ -2,6 +2,9 @@
#include "DrawingProgramLayerListItem.hpp"
#include "DrawingProgramLayer.hpp"
#include <Helpers/Parallel.hpp>
#include "DrawingProgramLayerManager.hpp"
#include "../DrawingProgram.hpp"
#include "../../World.hpp"
void DrawingProgramLayerFolder::draw(SkCanvas* canvas, const DrawData& drawData) const {
for(auto& p : (*folderList) | std::views::reverse)
@ -24,11 +27,6 @@ void DrawingProgramLayerFolder::set_to_erase() {
listItem.obj->set_to_erase();
}
void DrawingProgramLayerFolder::commit_update_dont_invalidate_cache(DrawingProgramLayerManager& layerMan) const {
for(auto& listItem : *folderList)
listItem.obj->commit_update_dont_invalidate_cache(layerMan);
}
void DrawingProgramLayerFolder::get_flattened_component_list(std::vector<CanvasComponentContainer::ObjInfo*>& objList) const {
for(auto& listItem : (*folderList) | std::views::reverse)
listItem.obj->get_flattened_component_list(objList);
@ -54,3 +52,20 @@ void DrawingProgramLayerFolder::scale_up(const WorldScalar& scaleUpAmount) {
for(auto& p : *folderList)
p.obj->scale_up(scaleUpAmount);
}
void DrawingProgramLayerFolder::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, DrawingProgramLayerManager& layerMan) {
folderList = layerMan.drawP.world.netObjMan.make_obj<NetworkingObjects::NetObjOrderedList<DrawingProgramLayerListItem>>();
uint32_t folderListSize;
a(folderListSize);
for(uint32_t i = 0; i < folderListSize; i++) {
DrawingProgramLayerListItem* item = new DrawingProgramLayerListItem();
item->load_file(a, version, layerMan);
folderList->push_back_and_send_create(folderList, item);
}
}
void DrawingProgramLayerFolder::save_file(cereal::PortableBinaryOutputArchive& a) const {
a(folderList->size());
for(auto& listItem : *folderList)
listItem.obj->save_file(a);
}

View file

@ -11,7 +11,6 @@ class DrawingProgramLayerFolder {
public:
void draw(SkCanvas* canvas, const DrawData& drawData) const;
void set_component_list_callbacks(DrawingProgramLayerManager& layerMan);
void commit_update_dont_invalidate_cache(DrawingProgramLayerManager& layerMan) const;
void get_flattened_component_list(std::vector<CanvasComponentContainer::ObjInfo*>& objList) const;
void set_to_erase();
NetworkingObjects::NetObjWeakPtr<DrawingProgramLayerListItem> get_initial_editing_layer() const;
@ -19,4 +18,7 @@ class DrawingProgramLayerFolder {
NetworkingObjects::NetObjOwnerPtr<NetworkingObjects::NetObjOrderedList<DrawingProgramLayerListItem>> folderList;
bool isFolderOpen = false;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, DrawingProgramLayerManager& layerMan);
void save_file(cereal::PortableBinaryOutputArchive& a) const;
};

View file

@ -46,13 +46,6 @@ void DrawingProgramLayerListItem::set_component_list_callbacks(DrawingProgramLay
layerData->set_component_list_callbacks(*this, layerMan);
}
void DrawingProgramLayerListItem::commit_update_dont_invalidate_cache(DrawingProgramLayerManager& layerMan) {
if(folderData)
folderData->commit_update_dont_invalidate_cache(layerMan);
else
layerData->commit_update_dont_invalidate_cache(layerMan);
}
void DrawingProgramLayerListItem::get_flattened_component_list(std::vector<CanvasComponentContainer::ObjInfo*>& objList) const {
if(folderData)
folderData->get_flattened_component_list(objList);
@ -99,6 +92,35 @@ DrawingProgramLayer& DrawingProgramLayerListItem::get_layer() const {
return *layerData;
}
void DrawingProgramLayerListItem::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, DrawingProgramLayerManager& layerMan) {
nameData = layerMan.drawP.world.netObjMan.make_obj<NameData>();
a(*nameData);
displayData = layerMan.drawP.world.netObjMan.make_obj<DisplayData>();
a(*displayData);
bool isFolder;
a(isFolder);
if(isFolder) {
folderData = std::make_unique<DrawingProgramLayerFolder>();
folderData->load_file(a, version, layerMan);
}
else {
layerData = std::make_unique<DrawingProgramLayer>();
layerData->load_file(a, version, layerMan);
}
}
void DrawingProgramLayerListItem::save_file(cereal::PortableBinaryOutputArchive& a) const {
a(*nameData);
a(*displayData);
a(static_cast<bool>(folderData));
if(folderData)
folderData->save_file(a);
else
layerData->save_file(a);
}
void DrawingProgramLayerListItem::draw(SkCanvas* canvas, const DrawData& drawData) const {
if(displayData->visible) {
SkPaint layerPaint;

View file

@ -23,7 +23,6 @@ class DrawingProgramLayerListItem {
void reassign_netobj_ids_call();
void set_to_erase();
void set_component_list_callbacks(DrawingProgramLayerManager &layerMan);
void commit_update_dont_invalidate_cache(DrawingProgramLayerManager& layerMan);
void draw(SkCanvas* canvas, const DrawData& drawData) const;
void set_name(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, const std::string& newName) const;
const std::string& get_name() const;
@ -34,6 +33,9 @@ class DrawingProgramLayerListItem {
void set_alpha(DrawingProgramLayerManager& layerMan, float newAlpha) const;
float get_alpha() const;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version, DrawingProgramLayerManager& layerMan);
void save_file(cereal::PortableBinaryOutputArchive& a) const;
void set_visible(DrawingProgramLayerManager& layerMan, bool newVisible) const;
bool get_visible() const;

View file

@ -1,18 +1,17 @@
#include "DrawingProgramLayerManager.hpp"
#include "../../World.hpp"
#include "Helpers/NetworkingObjects/NetObjOrderedList.hpp"
#include "Helpers/Parallel.hpp"
DrawingProgramLayerManager::DrawingProgramLayerManager(DrawingProgram& drawProg):
drawP(drawProg), // initialize drawP first for next objects to be initialized properly
listGUI(*this)
{}
void DrawingProgramLayerManager::init() {
if(drawP.world.netObjMan.is_server()) {
layerTreeRoot = drawP.world.netObjMan.make_obj_from_ptr<DrawingProgramLayerListItem>(new DrawingProgramLayerListItem(drawP.world.netObjMan, "ROOT", true));
layerTreeRoot->get_folder().set_component_list_callbacks(*this); // Only need to call set_component_list_callbacks on root, and the rest will get the callbacks set as well
editingLayer = layerTreeRoot->get_folder().folderList->emplace_back_direct(layerTreeRoot->get_folder().folderList, drawP.world.netObjMan, "First Layer", false)->obj;
}
void DrawingProgramLayerManager::server_init_no_file() {
layerTreeRoot = drawP.world.netObjMan.make_obj_from_ptr<DrawingProgramLayerListItem>(new DrawingProgramLayerListItem(drawP.world.netObjMan, "ROOT", true));
layerTreeRoot->get_folder().set_component_list_callbacks(*this); // Only need to call set_component_list_callbacks on root, and the rest will get the callbacks set as well
editingLayer = layerTreeRoot->get_folder().folderList->emplace_back_direct(layerTreeRoot->get_folder().folderList, drawP.world.netObjMan, "First Layer", false)->obj;
}
void DrawingProgramLayerManager::scale_up(const WorldScalar& scaleUpAmount) {
@ -25,8 +24,14 @@ void DrawingProgramLayerManager::write_components_server(cereal::PortableBinaryO
void DrawingProgramLayerManager::read_components_client(cereal::PortableBinaryInputArchive& a) {
layerTreeRoot = drawP.world.netObjMan.read_create_message<DrawingProgramLayerListItem>(a, nullptr);
layerTreeRoot->commit_update_dont_invalidate_cache(*this);
commitUpdateOnComponentInsert = false;
layerTreeRoot->set_component_list_callbacks(*this);
commitUpdateOnComponentInsert = true;
auto flattenedCompList = get_flattened_component_list();
parallel_loop_container(flattenedCompList, [&drawP = drawP](CanvasComponentContainer::ObjInfo* comp) {
comp->obj->commit_update_dont_invalidate_cache(drawP);
});
drawP.rebuild_cache();
editingLayer = layerTreeRoot->get_folder().get_initial_editing_layer();
}
@ -97,3 +102,21 @@ CanvasComponentContainer::ObjInfo* DrawingProgramLayerManager::add_component_to_
return &(*editLayerPtr->get_layer().components->push_back_and_send_create(editLayerPtr->get_layer().components, newObj));
}
void DrawingProgramLayerManager::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) {
layerTreeRoot = drawP.world.netObjMan.make_obj_from_ptr<DrawingProgramLayerListItem>(new DrawingProgramLayerListItem());
layerTreeRoot->load_file(a, version, *this);
commitUpdateOnComponentInsert = false;
layerTreeRoot->get_folder().set_component_list_callbacks(*this); // Only need to call set_component_list_callbacks on root, and the rest will get the callbacks set as well
commitUpdateOnComponentInsert = true;
auto flattenedCompList = get_flattened_component_list();
parallel_loop_container(flattenedCompList, [&drawP = drawP](CanvasComponentContainer::ObjInfo* comp) {
comp->obj->commit_update_dont_invalidate_cache(drawP);
});
drawP.rebuild_cache();
editingLayer = layerTreeRoot->get_folder().get_initial_editing_layer();
}
void DrawingProgramLayerManager::save_file(cereal::PortableBinaryOutputArchive& a) const {
layerTreeRoot->save_file(a);
}

View file

@ -13,6 +13,7 @@ class DrawingProgramLayerManager {
NetworkingObjects::NetObjOwnerPtr<DrawingProgramLayerListItem> layerTreeRoot;
NetworkingObjects::NetObjWeakPtr<DrawingProgramLayerListItem> editingLayer;
void set_initial_editing_layer();
bool commitUpdateOnComponentInsert = true;
public:
enum class LayerSelector {
ALL_VISIBLE_LAYERS,
@ -20,7 +21,7 @@ class DrawingProgramLayerManager {
};
DrawingProgramLayerManager(DrawingProgram& drawProg);
void init();
void server_init_no_file();
void draw(SkCanvas* canvas, const DrawData& drawData);
void write_components_server(cereal::PortableBinaryOutputArchive& a);
void read_components_client(cereal::PortableBinaryInputArchive& a);
@ -39,6 +40,9 @@ class DrawingProgramLayerManager {
CanvasComponentContainer::ObjInfoIterator get_edited_layer_end_iterator();
bool component_passes_layer_selector(CanvasComponentContainer::ObjInfo* c, LayerSelector layerSelector);
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version);
void save_file(cereal::PortableBinaryOutputArchive& a) const;
bool layer_tree_root_exists();
const DrawingProgramLayerListItem& get_layer_root();
uint32_t total_component_count();

View file

@ -5,9 +5,8 @@
GridManager::GridManager(World& w):
world(w) {}
void GridManager::init() {
if(world.netObjMan.is_server())
grids = world.netObjMan.make_obj<NetworkingObjects::NetObjOrderedList<WorldGrid>>();
void GridManager::server_init_no_file() {
grids = world.netObjMan.make_obj<NetworkingObjects::NetObjOrderedList<WorldGrid>>();
}
void GridManager::add_default_grid(const std::string& newName) {
@ -71,3 +70,21 @@ void GridManager::scale_up(const WorldScalar& scaleUpAmount) {
grids->at(i)->obj->scale_up(scaleUpAmount);
}
}
void GridManager::save_file(cereal::PortableBinaryOutputArchive& a) const {
a(grids->size());
for(auto& item : *grids)
a(*item.obj);
}
void GridManager::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) {
grids = world.netObjMan.make_obj<NetworkingObjects::NetObjOrderedList<WorldGrid>>();
uint32_t gridSize;
a(gridSize);
for(uint32_t i = 0; i < gridSize; i++) {
WorldGrid* g = new WorldGrid;
a(*g);
grids->push_back_and_send_create(grids, g);
}
}

View file

@ -8,7 +8,7 @@ class World;
class GridManager {
public:
GridManager(World& w);
void init();
void server_init_no_file();
void add_default_grid(const std::string& newName);
@ -32,6 +32,8 @@ class GridManager {
void draw_front(SkCanvas* canvas, const DrawData& drawData);
void draw_coordinates(SkCanvas* canvas, const DrawData& drawData);
void scale_up(const WorldScalar& scaleUpAmount);
void save_file(cereal::PortableBinaryOutputArchive& a) const;
void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version);
NetworkingObjects::NetObjOwnerPtr<NetworkingObjects::NetObjOrderedList<WorldGrid>> grids;
World& world;

View file

@ -71,7 +71,7 @@ void MainProgram::update() {
const std::filesystem::path& droppedFilePath = droppedItem.dataPath.value();
if(droppedFilePath.has_extension() && droppedFilePath.extension().string() == std::string("." + World::FILE_EXTENSION)) {
new_tab({
.conType = World::CONNECTIONTYPE_LOCAL,
.isClient = false,
.filePathSource = droppedFilePath
}, true);
return true;
@ -93,7 +93,7 @@ void MainProgram::update() {
worldIndex = worlds.size() - 1;
if(worlds.size() == 0)
new_tab({
.conType = World::CONNECTIONTYPE_LOCAL
.isClient = false
}, true);
std::shared_ptr<World> oldWorld = world;
@ -131,7 +131,7 @@ void MainProgram::update() {
void MainProgram::update_display_names() {
for(auto& w : worlds) {
if(!w->network_being_used())
if(!w->netObjMan.is_connected())
w->ownClientData->set_display_name(displayName);
}
}
@ -284,7 +284,7 @@ void MainProgram::draw(SkCanvas* canvas) {
bool MainProgram::network_being_used() {
for(auto& w : worlds) {
if(w->network_being_used())
if(w->netObjMan.is_connected())
return true;
}
return false;
@ -292,7 +292,7 @@ bool MainProgram::network_being_used() {
bool MainProgram::net_server_hosted() {
for(auto& w : worlds) {
if(w->conType == World::CONNECTIONTYPE_SERVER)
if(w->netServer)
return true;
}
return false;

View file

@ -18,14 +18,14 @@ ResourceManager::ResourceManager(World& initWorld):
{}
void ResourceManager::init_client_callbacks() {
world.con.client_add_recv_callback(SERVER_NEW_RESOURCE_ID, [&](cereal::PortableBinaryInputArchive& message) {
world.netClient->add_recv_callback(SERVER_NEW_RESOURCE_ID, [&](cereal::PortableBinaryInputArchive& message) {
NetworkingObjects::NetObjID idBeingRetrieved;
message(idBeingRetrieved);
// There is a scenario where the resource id and data messages can be sent twice for the same resource (a resource can be sent early before CLIENT_INITIAL_DATA is sent, and then resent with CLIENT_INITIAL_DATA), so check if resource already exists, and only keep track of the ID if the resource doesn't exist yet
if(!world.netObjMan.get_obj_temporary_ref_from_id<ResourceData>(idBeingRetrieved))
resourcesBeingRetrieved.emplace(idBeingRetrieved, std::weak_ptr<NetServer::ClientData>());
});
world.con.client_add_recv_callback(SERVER_NEW_RESOURCE_DATA, [&](cereal::PortableBinaryInputArchive& message) {
world.netClient->add_recv_callback(SERVER_NEW_RESOURCE_DATA, [&](cereal::PortableBinaryInputArchive& message) {
if(!resourcesBeingRetrieved.empty()) { // If the resource was sent for the second time, this will be empty, so we can ignore the message
ResourceData newResource;
message(newResource);
@ -69,8 +69,8 @@ float ResourceManager::get_resource_retrieval_progress(const NetworkingObjects::
return 0.0f;
return static_cast<float>(progressBytes.downloadedBytes) / static_cast<float>(progressBytes.totalBytes);
}
else if(world.con.client_exists() && !world.con.is_client_disconnected()) {
NetLibrary::DownloadProgress progressBytes = world.con.client_get_resource_retrieval_progress();
else if(world.netClient) {
NetLibrary::DownloadProgress progressBytes = world.netClient->get_progress_into_fragmented_message(RESOURCE_COMMAND_CHANNEL);
if(progressBytes.totalBytes == 0)
return 0.0f;
return static_cast<float>(progressBytes.downloadedBytes) / static_cast<float>(progressBytes.totalBytes);
@ -133,9 +133,9 @@ const NetworkingObjects::NetObjOwnerPtr<ResourceData>& ResourceManager::add_reso
world.netServer->send_items_to_all_clients(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_ID, resourceInsert.get_net_id());
world.netServer->send_items_to_all_clients(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_DATA, resource);
}
else {
world.con.client_send_items_to_server(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_ID, resourceInsert.get_net_id());
world.con.client_send_items_to_server(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_DATA, resource);
else if(world.netClient) {
world.netClient->send_items_to_server(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_ID, resourceInsert.get_net_id());
world.netClient->send_items_to_server(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_DATA, resource);
}
return resourceInsert;
}

View file

@ -1,5 +1,5 @@
#include "ScaleUpCanvas.hpp"
WorldScalar get_canvas_scale_up_amount(uint32_t newGridSize, uint32_t oldGridSize) {
return FixedPoint::pow_int(CANVAS_SCALE_UP_STEP, newGridSize - oldGridSize);
return FixedPoint::pow_int(WorldScalar(10000), newGridSize - oldGridSize);
}

View file

@ -469,10 +469,10 @@ void Toolbar::top_toolbar() {
}
std::vector<std::pair<std::string, std::string>> tabNames;
for(size_t i = 0; i < main.worlds.size(); i++)
tabNames.emplace_back(main.worlds[i]->network_being_used() ? "data/icons/network.svg" : "", main.worlds[i]->name);
tabNames.emplace_back(main.worlds[i]->netObjMan.is_connected() ? "data/icons/network.svg" : "", main.worlds[i]->name);
std::optional<size_t> closedTab;
gui.tab_list("file tab list", tabNames, main.worldIndex, closedTab);
if(main.world->network_being_used() && gui.svg_icon_button_transparent("Player List Toggle Button", "data/icons/list.svg", playerMenuOpen))
if(main.world->netObjMan.is_connected() && gui.svg_icon_button_transparent("Player List Toggle Button", "data/icons/list.svg", playerMenuOpen))
playerMenuOpen = !playerMenuOpen;
if(gui.svg_icon_button_transparent("Menu Undo Button", "data/icons/undo.svg"))
main.world->undo_with_checks();
@ -528,7 +528,7 @@ void Toolbar::top_toolbar() {
gui.obstructing_window();
if(gui.text_button_left_transparent("new file local", "New File")) {
main.new_tab({
.conType = World::CONNECTIONTYPE_LOCAL
.isClient = false
}, true);
}
if(gui.text_button_left_transparent("save file", "Save"))
@ -536,7 +536,7 @@ void Toolbar::top_toolbar() {
if(gui.text_button_left_transparent("save as file", "Save As"))
save_as_func();
if(gui.text_button_left_transparent("open file", "Open"))
open_world_file(World::CONNECTIONTYPE_LOCAL, "", "");
open_world_file(false, "", "");
if(gui.text_button_left_transparent("screenshot", "Take Screenshot"))
main.world->drawProg.switch_to_tool(DrawingProgramToolType::SCREENSHOT);
if(gui.text_button_left_transparent("add image or file to canvas", "Add Image/File to Canvas")) {
@ -555,7 +555,7 @@ void Toolbar::top_toolbar() {
});
#endif
}
if(main.world->network_being_used()) {
if(main.world->netObjMan.is_connected()) {
if(gui.text_button_left_transparent("lobby info", "Lobby Info")) {
optionsMenuOpen = true;
optionsMenuType = LOBBY_INFO_MENU;
@ -877,7 +877,7 @@ std::unique_ptr<skia::textlayout::Paragraph> Toolbar::build_paragraph_from_chat_
void Toolbar::chat_box() {
constexpr float CHATBOX_WIDTH = 700;
if(main.world->network_being_used()) {
if(main.world->netObjMan.is_connected()) {
CLAY_AUTO_ID({
.layout = {
.layoutDirection = CLAY_LEFT_TO_RIGHT
@ -1297,15 +1297,15 @@ void Toolbar::player_list() {
}
}
void Toolbar::open_world_file(int conType, const std::string& netSource, const std::string& serverLocalID2) {
void Toolbar::open_world_file(bool isClient, const std::string& netSource, const std::string& serverLocalID2) {
#ifdef __EMSCRIPTEN__
static struct UploadData {
int cT;
bool iC;
std::string nS;
std::string sLID;
MainProgram* main;
} uploadData;
uploadData.cT = conType;
uploadData.iC = isClient;
uploadData.nS = netSource;
uploadData.sLID = serverLocalID2;
uploadData.main = &main;
@ -1313,7 +1313,7 @@ void Toolbar::open_world_file(int conType, const std::string& netSource, const s
if(!buffer.empty()) {
UploadData* uD = (UploadData*)callbackData;
uD->main->new_tab({
.conType = (World::ConnectionType)uD->cT,
.isClient = uD->iC,
.filePathSource = std::filesystem::path(fileName),
.netSource = uD->nS,
.serverLocalID = uD->sLID,
@ -1322,9 +1322,9 @@ void Toolbar::open_world_file(int conType, const std::string& netSource, const s
}
}, &uploadData);
#else
open_file_selector("Open", {{"Any File", "*"}, {"InfiniPaint Canvas", World::FILE_EXTENSION}}, [&, conType = conType, netSource = netSource, serverLocalID2 = serverLocalID2](const std::filesystem::path& p, const auto& e) {
open_file_selector("Open", {{"Any File", "*"}, {"InfiniPaint Canvas", World::FILE_EXTENSION}}, [&, isClient = isClient, netSource = netSource, serverLocalID2 = serverLocalID2](const std::filesystem::path& p, const auto& e) {
main.new_tab({
.conType = (World::ConnectionType)conType,
.isClient = isClient,
.filePathSource = p,
.netSource = netSource,
.serverLocalID = serverLocalID2
@ -1378,7 +1378,7 @@ void Toolbar::options_menu() {
Logger::get().log("USERINFO", "Connect issue: Can't connect to your own address");
else {
main.new_tab({
.conType = World::CONNECTIONTYPE_CLIENT,
.isClient = true,
.netSource = serverToConnectTo
}, true);
optionsMenuOpen = false;
@ -1647,7 +1647,7 @@ void Toolbar::options_menu() {
}) {
gui.push_id("lobby info menu");
gui.obstructing_window();
if(!main.world || !main.world->network_being_used())
if(!main.world || !main.world->netObjMan.is_connected())
optionsMenuOpen = false;
else {
std::string oldS = main.world->netSource;

View file

@ -109,7 +109,7 @@ class Toolbar {
void file_picker_gui();
void performance_metrics();
bool color_palette(const std::string& id, Vector4f* color, bool& hoveringOnDropdown);
void open_world_file(int conType, const std::string& netSource, const std::string& serverLocalID);
void open_world_file(bool isClient, const std::string& netSource, const std::string& serverLocalID);
void load_default_palette();
void load_default_theme();
void about_menu_gui();

View file

@ -10,6 +10,7 @@ VersionNumber header_to_version_number(const std::string& header) {
m["INFPNT000002"] = VersionNumber(0, 1, 0);
m["INFPNT000003"] = VersionNumber(0, 2, 0);
m["INFPNT000004"] = VersionNumber(0, 3, 0);
m["INFPNT000005"] = VersionNumber(0, 4, 0);
}
auto it = m.find(header);
if(it == m.end())

View file

@ -10,7 +10,7 @@ namespace VersionConstants {
VersionNumber header_to_version_number(const std::string& header);
constexpr int SAVEFILE_HEADER_LEN = 12; // DO NOT CHANGE THIS HEADER LENGTH
const std::string CURRENT_SAVEFILE_HEADER = "INFPNT000004"; // Change whenever the save file is incompatible with the previous version
const std::string CURRENT_VERSION_STRING = "0.3.1";
constexpr VersionNumber CURRENT_VERSION_NUMBER(0, 3, 1);
const std::string CURRENT_SAVEFILE_HEADER = "INFPNT000005"; // Change whenever the save file is incompatible with the previous version
const std::string CURRENT_VERSION_STRING = "0.4.0";
constexpr VersionNumber CURRENT_VERSION_NUMBER(0, 4, 0);
}

View file

@ -36,7 +36,7 @@
#endif
World::World(MainProgram& initMain, OpenWorldInfo& worldInfo):
netObjMan(worldInfo.conType != CONNECTIONTYPE_CLIENT),
netObjMan(!worldInfo.isClient),
main(initMain),
rMan(*this),
drawProg(*this),
@ -45,52 +45,31 @@ World::World(MainProgram& initMain, OpenWorldInfo& worldInfo):
canvasTheme(*this)
{
init_net_obj_type_list();
init_client_data_list();
gridMan.init();
bMan.init();
drawProg.init();
canvasTheme.init();
netSource = worldInfo.netSource;
if(worldInfo.conType == CONNECTIONTYPE_CLIENT || worldInfo.conType == CONNECTIONTYPE_SERVER)
main.init_net_library();
drawData.rMan = &rMan;
drawData.main = &main;
conType = worldInfo.conType;
switch(conType) {
case CONNECTIONTYPE_CLIENT: {
clientStillConnecting = true;
con.connect_p2p(*this, netSource);
set_name("");
break;
}
case CONNECTIONTYPE_LOCAL: {
if(worldInfo.filePathSource.has_value())
load_from_file(worldInfo.filePathSource.value(), worldInfo.fileDataBuffer);
set_name(name);
break;
}
case CONNECTIONTYPE_SERVER: {
break;
}
if(worldInfo.isClient)
init_client(worldInfo.netSource);
else {
init_client_data_list();
if(worldInfo.filePathSource.has_value())
load_from_file(worldInfo.filePathSource.value(), worldInfo.fileDataBuffer);
else
load_empty_canvas();
set_name(name);
}
init_client_callbacks();
con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_INITIAL_DATA, main.displayName);
}
void World::init_client_data_list() {
if(netObjMan.is_server()) {
clients = netObjMan.make_obj<NetworkingObjects::NetObjUnorderedSet<ClientData>>();
ownClientData = clients->emplace_direct(clients, ClientData::InitStruct{
.cursorColor = get_random_cursor_color(),
.displayName = main.displayName
});
init_client_data_list_callbacks();
}
clients = netObjMan.make_obj<NetworkingObjects::NetObjUnorderedSet<ClientData>>();
ownClientData = clients->emplace_direct(clients, ClientData::InitStruct{
.cursorColor = get_random_cursor_color(),
.displayName = main.displayName
});
init_client_data_list_callbacks();
}
Vector3f World::get_random_cursor_color() {
@ -124,56 +103,18 @@ void World::init_net_obj_type_list() {
NetworkingObjects::register_unordered_set_class<ClientData>(netObjMan);
}
void World::init_server_callbacks() {
rMan.init_server_callbacks();
drawProg.init_server_callbacks();
netServer->add_recv_callback(SERVER_INITIAL_DATA, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
ClientData::InitStruct newClientData;
newClientData.cursorColor = get_random_cursor_color();
message(newClientData.displayName);
ensure_display_name_unique(newClientData.displayName);
void World::init_client(const std::string& serverFullID) {
main.init_net_library();
clientStillConnecting = true;
netClient = std::make_shared<NetClient>(serverFullID);
lastKeepAliveSent = std::chrono::steady_clock::now();
NetLibrary::register_client(netClient);
netObjMan.set_client(netClient, SERVER_UPDATE_NETWORK_OBJECT, SERVER_UPDATE_MANY_NETWORK_OBJECTS);
set_name("");
newClientData.camCoords = ownClientData->get_cam_coords();
newClientData.windowSize = ownClientData->get_window_size();
newClientData.gridSize = ownClientData->get_grid_size();
NetworkingObjects::NetObjTemporaryPtr<ClientData> clientDataObjPtr = clients->emplace_direct(clients, newClientData);
client->customID = clientDataObjPtr.get_net_id().data;
auto ss(std::make_shared<std::stringstream>());
{
cereal::PortableBinaryOutputArchive a(*ss);
a(CLIENT_INITIAL_DATA, name, clientDataObjPtr.get_net_id());
bMan.bookmarkListRoot.write_create_message(a);
gridMan.grids.write_create_message(a);
drawProg.write_components_server(a);
canvasTheme.write_create_message(a);
clients.write_create_message(a);
}
netServer->send_string_stream_to_client(client, RELIABLE_COMMAND_CHANNEL, ss);
for(auto& r : rMan.resource_list()) {
netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_ID, r.get_net_id());
netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_DATA, *r);
}
});
netServer->add_recv_callback(SERVER_UPDATE_NETWORK_OBJECT, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
netObjMan.read_update_message(message, client);
});
netServer->add_recv_callback(SERVER_UPDATE_MANY_NETWORK_OBJECTS, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
netObjMan.read_many_update_message(message, client);
});
netServer->add_recv_callback(SERVER_KEEP_ALIVE, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
});
netServer->add_disconnect_callback([&](std::shared_ptr<NetServer::ClientData> client) {
NetworkingObjects::NetObjID idToErase;
idToErase.data = client->customID;
clients->erase(clients, idToErase);
});
}
void World::init_client_callbacks() {
rMan.init_client_callbacks();
drawProg.init_client_callbacks();
con.client_add_recv_callback(CLIENT_INITIAL_DATA, [&](cereal::PortableBinaryInputArchive& message) {
netClient->add_recv_callback(CLIENT_INITIAL_DATA, [&](cereal::PortableBinaryInputArchive& message) {
std::string fileDisplayName;
NetworkingObjects::NetObjID clientDataObjID;
message(fileDisplayName, clientDataObjID);
@ -189,43 +130,22 @@ void World::init_client_callbacks() {
clientStillConnecting = false;
});
con.client_add_recv_callback(CLIENT_UPDATE_NETWORK_OBJECT, [&](cereal::PortableBinaryInputArchive& message) {
netClient->add_recv_callback(CLIENT_UPDATE_NETWORK_OBJECT, [&](cereal::PortableBinaryInputArchive& message) {
netObjMan.read_update_message(message, nullptr);
});
con.client_add_recv_callback(CLIENT_UPDATE_MANY_NETWORK_OBJECTS, [&](cereal::PortableBinaryInputArchive& message) {
netClient->add_recv_callback(CLIENT_UPDATE_MANY_NETWORK_OBJECTS, [&](cereal::PortableBinaryInputArchive& message) {
netObjMan.read_many_update_message(message, nullptr);
});
con.client_add_recv_callback(CLIENT_KEEP_ALIVE, [&](cereal::PortableBinaryInputArchive& message) {
netClient->add_recv_callback(CLIENT_KEEP_ALIVE, [&](cereal::PortableBinaryInputArchive& message) {
});
netClient->send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_INITIAL_DATA, main.displayName);
}
void World::focus_update() {
con.update();
if(netServer) {
if(netServer->is_disconnected()) {
Logger::get().log("USERINFO", "Host connection failed");
netSource.clear();
netServer = nullptr;
conType = CONNECTIONTYPE_LOCAL;
con = ConnectionManager();
netObjMan.disconnect();
}
else {
netServer->update();
if(std::chrono::steady_clock::now() - lastKeepAliveSent > std::chrono::seconds(2)) {
netServer->send_items_to_all_clients(UNRELIABLE_COMMAND_CHANNEL, CLIENT_KEEP_ALIVE);
lastKeepAliveSent = std::chrono::steady_clock::now();
}
}
}
if(con.is_client_disconnected()) {
Logger::get().log("USERINFO", "Client connection failed");
setToDestroy = true;
netObjMan.disconnect();
connection_update();
if(setToDestroy)
return;
}
if(!clientStillConnecting) {
delayedUpdateObjectManager.update(netObjMan);
@ -253,6 +173,36 @@ void World::focus_update() {
redo_with_checks();
}
void World::connection_update() {
if(netServer) {
if(netServer->is_disconnected()) {
Logger::get().log("USERINFO", "Host connection failed");
netSource.clear();
netServer = nullptr;
netObjMan.disconnect();
}
else {
netServer->update();
if(std::chrono::steady_clock::now() - lastKeepAliveSent > std::chrono::seconds(2)) {
netServer->send_items_to_all_clients(UNRELIABLE_COMMAND_CHANNEL, CLIENT_KEEP_ALIVE);
lastKeepAliveSent = std::chrono::steady_clock::now();
}
}
}
else if(netClient) {
if(netClient->is_disconnected()) {
Logger::get().log("USERINFO", "Client connection failed");
setToDestroy = true;
netObjMan.disconnect();
}
netClient->update();
if(std::chrono::steady_clock::now() - lastKeepAliveSent > std::chrono::seconds(2)) {
netClient->send_items_to_server(UNRELIABLE_COMMAND_CHANNEL, SERVER_KEEP_ALIVE);
lastKeepAliveSent = std::chrono::steady_clock::now();
}
}
}
void World::undo_with_checks() {
if(!clientStillConnecting && !drawProg.prevent_undo_or_redo())
undo.undo();
@ -264,18 +214,9 @@ void World::redo_with_checks() {
}
void World::unfocus_update() {
con.update();
if(con.is_client_disconnected()) {
Logger::get().log("USERINFO", "Client connection failed");
setToDestroy = true;
}
if(netServer) {
netServer->update();
if(std::chrono::steady_clock::now() - lastKeepAliveSent > std::chrono::seconds(2)) {
netServer->send_items_to_all_clients(UNRELIABLE_COMMAND_CHANNEL, CLIENT_KEEP_ALIVE);
lastKeepAliveSent = std::chrono::steady_clock::now();
}
}
connection_update();
if(setToDestroy)
return;
}
void World::send_chat_message(const std::string& message) {
@ -302,10 +243,6 @@ void World::early_destroy() {
//con.early_destroy();
}
bool World::network_being_used() {
return conType != CONNECTIONTYPE_LOCAL;
}
void World::set_name(const std::string& n) {
if(n.empty())
name = "New File";
@ -353,15 +290,55 @@ void World::ensure_display_name_unique(std::string& displayName) {
}
void World::start_hosting(const std::string& initNetSource, const std::string& serverLocalID) {
if(conType != CONNECTIONTYPE_LOCAL)
return;
main.init_net_library();
netServer = std::make_shared<NetServer>(serverLocalID);
lastKeepAliveSent = std::chrono::steady_clock::now();
NetLibrary::register_server(netServer);
netObjMan.set_server(netServer, CLIENT_UPDATE_NETWORK_OBJECT, CLIENT_UPDATE_MANY_NETWORK_OBJECTS);
conType = CONNECTIONTYPE_SERVER;
netSource = initNetSource;
init_server_callbacks();
rMan.init_server_callbacks();
drawProg.init_server_callbacks();
netServer->add_recv_callback(SERVER_INITIAL_DATA, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
ClientData::InitStruct newClientData;
newClientData.cursorColor = get_random_cursor_color();
message(newClientData.displayName);
ensure_display_name_unique(newClientData.displayName);
newClientData.camCoords = ownClientData->get_cam_coords();
newClientData.windowSize = ownClientData->get_window_size();
newClientData.gridSize = ownClientData->get_grid_size();
NetworkingObjects::NetObjTemporaryPtr<ClientData> clientDataObjPtr = clients->emplace_direct(clients, newClientData);
client->customID = clientDataObjPtr.get_net_id().data;
auto ss(std::make_shared<std::stringstream>());
{
cereal::PortableBinaryOutputArchive a(*ss);
a(CLIENT_INITIAL_DATA, name, clientDataObjPtr.get_net_id());
bMan.bookmarkListRoot.write_create_message(a);
gridMan.grids.write_create_message(a);
drawProg.write_components_server(a);
canvasTheme.write_create_message(a);
clients.write_create_message(a);
}
netServer->send_string_stream_to_client(client, RELIABLE_COMMAND_CHANNEL, ss);
for(auto& r : rMan.resource_list()) {
netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_ID, r.get_net_id());
netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_DATA, *r);
}
});
netServer->add_recv_callback(SERVER_UPDATE_NETWORK_OBJECT, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
netObjMan.read_update_message(message, client);
});
netServer->add_recv_callback(SERVER_UPDATE_MANY_NETWORK_OBJECTS, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
netObjMan.read_many_update_message(message, client);
});
netServer->add_recv_callback(SERVER_KEEP_ALIVE, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
});
netServer->add_disconnect_callback([&](std::shared_ptr<NetServer::ClientData> client) {
NetworkingObjects::NetObjID idToErase;
idToErase.data = client->customID;
clients->erase(clients, idToErase);
});
}
void World::save_to_file(const std::filesystem::path& filePathToSaveAt) {
@ -406,6 +383,13 @@ void World::save_to_file(const std::filesystem::path& filePathToSaveAt) {
}
}
void World::load_empty_canvas() {
gridMan.server_init_no_file();
bMan.server_init_no_file();
drawProg.server_init_no_file();
canvasTheme.server_init_no_file();
}
void World::load_from_file(const std::filesystem::path& filePathToLoadFrom, std::string_view buffer) {
filePath = force_extension_on_path(filePathToLoadFrom, FILE_EXTENSION);
@ -444,33 +428,19 @@ void World::load_from_file(const std::filesystem::path& filePathToLoadFrom, std:
}
void World::save_file(cereal::PortableBinaryOutputArchive& a) const {
a(drawData.cam.c, main.window.size.cast<float>().eval());
//a(convert_vec3<Vector3f>(canvasTheme.backColor));
drawData.cam.save_file(a, *this);
canvasTheme.save_file(a);
drawProg.save_file(a);
bMan.save_file(a);
gridMan.save_file(a);
}
void World::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version) {
CoordSpaceHelper coordsToJumpTo;
Vector2f windowSizeToJumpTo;
a(coordsToJumpTo, windowSizeToJumpTo);
//if(version < VersionNumber(0, 1, 0))
// set_canvas_background_color(DEFAULT_CANVAS_BACKGROUND_COLOR);
//else {
// Vector3f canvasBackColor;
// a(canvasBackColor);
// const Vector3f OLD_DEFAULT_CANVAS_BACKGROUND_COLOR{0.12f, 0.12f, 0.12f};
// if(version < VersionNumber(0, 3, 0) && canvasBackColor == OLD_DEFAULT_CANVAS_BACKGROUND_COLOR)
// set_canvas_background_color(DEFAULT_CANVAS_BACKGROUND_COLOR);
// else
// set_canvas_background_color(canvasBackColor);
//}
drawData.cam.smooth_move_to(*this, coordsToJumpTo, windowSizeToJumpTo, true);
drawData.cam.load_file(a, version, *this);
canvasTheme.load_file(a, version);
drawProg.load_file(a, version);
//a(bMan);
//if(version >= VersionNumber(0, 2, 0))
// a(gridMan);
bMan.load_file(a, version);
gridMan.load_file(a, version);
}
WorldScalar World::calculate_zoom_from_uniform_zoom(WorldScalar uniformZoom, WorldVec oldWindowSize) {

View file

@ -5,13 +5,13 @@
#include "UndoManager.hpp"
#include "Bookmarks/BookmarkManager.hpp"
#include "ResourceManager.hpp"
#include "ConnectionManager.hpp"
#include "DrawingProgram/DrawingProgram.hpp"
#include "Toolbar.hpp"
#include "SharedTypes.hpp"
#include "CanvasTheme.hpp"
#include "GridManager.hpp"
#include <Helpers/NetworkingObjects/NetObjManager.hpp>
#include <chrono>
#include <filesystem>
#include "ClientData.hpp"
@ -24,14 +24,8 @@ class World {
static constexpr std::string FILE_EXTENSION = "infpnt";
static constexpr size_t CHAT_SIZE = 10;
enum ConnectionType : int {
CONNECTIONTYPE_CLIENT,
CONNECTIONTYPE_SERVER,
CONNECTIONTYPE_LOCAL
};
struct OpenWorldInfo {
ConnectionType conType;
bool isClient;
std::optional<std::filesystem::path> filePathSource;
std::string netSource;
std::string serverLocalID;
@ -52,7 +46,6 @@ class World {
ResourceManager rMan;
DrawingProgram drawProg;
BookmarkManager bMan;
ConnectionManager con;
GridManager gridMan;
std::deque<Toolbar::ChatMessage> chatMessages;
@ -75,9 +68,6 @@ class World {
void draw(SkCanvas* canvas);
void early_destroy();
bool network_being_used();
ConnectionType conType;
bool clientStillConnecting = false;
void save_to_file(const std::filesystem::path& filePathToSaveAt);
@ -101,19 +91,23 @@ class World {
NetworkingObjects::DelayUpdateSerializedClassManager delayedUpdateObjectManager;
std::shared_ptr<NetServer> netServer;
std::shared_ptr<NetClient> netClient;
private:
void load_empty_canvas();
Vector3f get_random_cursor_color();
void init_client_data_list();
void init_client_data_list_callbacks();
void init_net_obj_type_list();
void init_client_callbacks();
void init_server_callbacks();
void init_client(const std::string& serverFullID);
void set_name(const std::string& n);
void draw_other_player_cursors(SkCanvas* canvas, const DrawData& drawData);
void ensure_display_name_unique(std::string& displayName);
void connection_update();
TimePoint timeToSendCameraData;
WorldVec mousePreviousWorldVec = {0, 0};
WorldVec mouseWorldMove = {0, 0};

View file

@ -526,13 +526,13 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
if(listOfFilesToOpenFromCommand.empty()) {
mS.m->new_tab({
.conType = World::CONNECTIONTYPE_LOCAL
.isClient = false
}, true);
}
else {
for(std::filesystem::path& f : listOfFilesToOpenFromCommand) {
mS.m->new_tab({
.conType = World::CONNECTIONTYPE_LOCAL,
.isClient = false,
.filePathSource = f
}, true);
}