Improved online performance for canvases with many components
This commit is contained in:
parent
8a36bc4b6d
commit
b6a25280e6
16 changed files with 406 additions and 183 deletions
|
|
@ -13,7 +13,7 @@ template <class T> std::weak_ptr<T> make_weak_ptr(std::shared_ptr<T> ptr) { retu
|
|||
#define RELIABLE_COMMAND_CHANNEL "reliableCommand"
|
||||
#define UNRELIABLE_COMMAND_CHANNEL "unreliableCommand"
|
||||
#define RESOURCE_COMMAND_CHANNEL "resourceCommand"
|
||||
#define MAIN_NETLIBRARY_CHANNEL "main00001"
|
||||
#define MAIN_NETLIBRARY_CHANNEL "main00002" // NOTE: Change this value whenever netcode is incompatible with the previous version
|
||||
|
||||
typedef uint8_t MessageCommandType;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ template <typename T, typename IDType> class CollabList {
|
|||
std::function<void()> updateCallback;
|
||||
std::function<void(const ObjectInfoPtr& c)> clientInsertCallback;
|
||||
std::function<void(const ObjectInfoPtr& c)> clientEraseCallback;
|
||||
std::function<void(const std::unordered_set<ObjectInfoPtr>& c)> clientEraseSetCallback;
|
||||
std::function<void(const std::vector<ObjectInfoPtr>& c)> clientInsertOrderedVectorCallback;
|
||||
std::function<void(uint64_t oldPos)> clientServerLastPosShiftCallback;
|
||||
|
||||
|
|
@ -33,27 +32,9 @@ template <typename T, typename IDType> class CollabList {
|
|||
obj->syncIgnore = false;
|
||||
}
|
||||
|
||||
T* get_item_by_id(IDType id) {
|
||||
auto clientFound = std::find_if(clientSideList.begin(), clientSideList.end(), [&](const auto& obj) {
|
||||
return (obj->id == id);
|
||||
});
|
||||
if(clientFound != clientSideList.end())
|
||||
return &((*clientFound)->obj);
|
||||
auto serverFound = std::find_if(serverSideList.begin(), serverSideList.end(), [&](const auto& obj) {
|
||||
return (obj->id == id);
|
||||
});
|
||||
if(serverFound != serverSideList.end())
|
||||
return &((*serverFound)->obj);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IDType get_id(const T& item) {
|
||||
auto clientFound = std::find_if(clientSideList.begin(), clientSideList.end(), [&](const auto& obj) {
|
||||
return (obj->obj == item);
|
||||
});
|
||||
if(clientFound != clientSideList.end())
|
||||
return (*clientFound)->id;
|
||||
return {0, 0};
|
||||
ObjectInfoPtr get_item_by_id(IDType id) {
|
||||
auto it = idToObjectMap.find(id);
|
||||
return (idToObjectMap.end() == it) ? nullptr : it->second;
|
||||
}
|
||||
|
||||
void client_erase_if(const std::function<bool(uint64_t, const std::shared_ptr<ObjectInfo>&)>& func) {
|
||||
|
|
@ -63,6 +44,7 @@ template <typename T, typename IDType> class CollabList {
|
|||
if(clientEraseCallback)
|
||||
clientEraseCallback(clientSideList[i]);
|
||||
clientSideList[i]->obj->collabListInfo.reset();
|
||||
idToObjectMap.erase(clientSideList[i]->id);
|
||||
clientSideList.erase(clientSideList.begin() + i);
|
||||
i--;
|
||||
if(updateCallback)
|
||||
|
|
@ -83,6 +65,7 @@ template <typename T, typename IDType> class CollabList {
|
|||
item->collabListInfo = newObj;
|
||||
|
||||
clientSideList.insert(clientSideList.begin() + newObj->pos, newObj);
|
||||
idToObjectMap.emplace(newObj->id, newObj);
|
||||
|
||||
client_pos_refresh_after_insert(newObj->pos);
|
||||
|
||||
|
|
@ -100,6 +83,7 @@ template <typename T, typename IDType> class CollabList {
|
|||
if(clientEraseCallback)
|
||||
clientEraseCallback(obj);
|
||||
erasedID = obj->id;
|
||||
idToObjectMap.erase(erasedID);
|
||||
obj->syncIgnore = true;
|
||||
obj->obj->collabListInfo.reset();
|
||||
erasedSomething = true;
|
||||
|
|
@ -120,6 +104,9 @@ template <typename T, typename IDType> class CollabList {
|
|||
if(objSet.contains(obj)) {
|
||||
obj->syncIgnore = true;
|
||||
obj->obj->collabListInfo.reset();
|
||||
idToObjectMap.erase(obj->id);
|
||||
if(clientEraseCallback)
|
||||
clientEraseCallback(obj);
|
||||
erasedSomething = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -129,8 +116,6 @@ template <typename T, typename IDType> class CollabList {
|
|||
complete_client_pos_refresh(false);
|
||||
if(updateCallback)
|
||||
updateCallback();
|
||||
if(clientEraseSetCallback)
|
||||
clientEraseSetCallback(objSet);
|
||||
for(auto& o : objSet)
|
||||
o->obj->collabListInfo.reset();
|
||||
}
|
||||
|
|
@ -145,19 +130,21 @@ template <typename T, typename IDType> class CollabList {
|
|||
objOrderedVector.front()->syncIgnore = true;
|
||||
objOrderedVector.front()->id = getNewIDFunc();
|
||||
objOrderedVector.front()->obj->collabListInfo = objOrderedVector.front();
|
||||
idToObjectMap.emplace(objOrderedVector.front()->id, objOrderedVector.front());
|
||||
|
||||
for(uint64_t i = 1; i < static_cast<uint64_t>(objOrderedVector.size()); i++) {
|
||||
auto& obj = objOrderedVector[i];
|
||||
obj->syncIgnore = true;
|
||||
obj->id = getNewIDFunc();
|
||||
obj->obj->collabListInfo = obj;
|
||||
idToObjectMap.emplace(obj->id, obj);
|
||||
if(obj->pos - objOrderedVector[startPoint]->pos != (i - startPoint)) {
|
||||
uint64_t insertPosition = std::max(clientSideList.size(), objOrderedVector[startPoint]->pos);
|
||||
uint64_t insertPosition = std::min(clientSideList.size(), objOrderedVector[startPoint]->pos);
|
||||
clientSideList.insert(clientSideList.begin() + insertPosition, objOrderedVector.begin() + startPoint, objOrderedVector.begin() + i);
|
||||
startPoint = i;
|
||||
}
|
||||
}
|
||||
clientSideList.insert(clientSideList.begin() + objOrderedVector[startPoint]->pos, objOrderedVector.begin() + startPoint, objOrderedVector.end());
|
||||
clientSideList.insert(clientSideList.begin() + std::min(clientSideList.size(), objOrderedVector[startPoint]->pos), objOrderedVector.begin() + startPoint, objOrderedVector.end());
|
||||
|
||||
complete_client_pos_refresh(false);
|
||||
if(updateCallback)
|
||||
|
|
@ -166,12 +153,55 @@ template <typename T, typename IDType> class CollabList {
|
|||
clientInsertOrderedVectorCallback(objOrderedVector);
|
||||
}
|
||||
|
||||
std::vector<bool> server_insert_ordered_vector(std::vector<ObjectInfoPtr> objOrderedVector) {
|
||||
if(objOrderedVector.empty())
|
||||
return std::vector<bool>();
|
||||
|
||||
std::vector<bool> didntExistPreviously(objOrderedVector.size(), true);
|
||||
|
||||
uint64_t startPoint = 0;
|
||||
auto foundInClient1 = idToObjectMap.emplace(objOrderedVector.front()->id, objOrderedVector.front());
|
||||
if(!foundInClient1.second) { // object already existed
|
||||
objOrderedVector.front() = foundInClient1.first->second;
|
||||
didntExistPreviously[0] = false;
|
||||
}
|
||||
objOrderedVector.front()->syncIgnore = false;
|
||||
objOrderedVector.front()->obj->collabListInfo = objOrderedVector.front();
|
||||
|
||||
for(uint64_t i = 1; i < static_cast<uint64_t>(objOrderedVector.size()); i++) {
|
||||
auto& obj = objOrderedVector[i];
|
||||
|
||||
auto foundInClient = idToObjectMap.emplace(obj->id, obj);
|
||||
if(!foundInClient.second) { // object already existed
|
||||
obj = foundInClient.first->second;
|
||||
didntExistPreviously[i] = false;
|
||||
}
|
||||
obj->syncIgnore = false;
|
||||
obj->obj->collabListInfo = obj;
|
||||
|
||||
if(obj->pos - objOrderedVector[startPoint]->pos != (i - startPoint)) {
|
||||
uint64_t insertPosition = std::min(clientSideList.size(), objOrderedVector[startPoint]->pos);
|
||||
clientSideList.insert(clientSideList.begin() + insertPosition, objOrderedVector.begin() + startPoint, objOrderedVector.begin() + i);
|
||||
uint64_t insertPositionServer = std::min(serverSideList.size(), objOrderedVector[startPoint]->pos);
|
||||
serverSideList.insert(serverSideList.begin() + insertPositionServer, objOrderedVector.begin() + startPoint, objOrderedVector.begin() + i);
|
||||
startPoint = i;
|
||||
}
|
||||
}
|
||||
clientSideList.insert(clientSideList.begin() + std::min(clientSideList.size(), objOrderedVector[startPoint]->pos), objOrderedVector.begin() + startPoint, objOrderedVector.end());
|
||||
serverSideList.insert(serverSideList.begin() + std::min(serverSideList.size(), objOrderedVector[startPoint]->pos), objOrderedVector.begin() + startPoint, objOrderedVector.end());
|
||||
|
||||
if(clientInsertOrderedVectorCallback)
|
||||
clientInsertOrderedVectorCallback(objOrderedVector);
|
||||
|
||||
sync();
|
||||
|
||||
return didntExistPreviously;
|
||||
}
|
||||
|
||||
bool server_insert(uint64_t pos, IDType id, const T& item) {
|
||||
auto foundInClient = std::find_if(clientSideList.begin(), clientSideList.end(), [&](const auto& clientObj) {
|
||||
return clientObj->id == id;
|
||||
});
|
||||
if(foundInClient != clientSideList.end()) {
|
||||
ObjectInfoPtr& o = *foundInClient;
|
||||
auto foundInClient = idToObjectMap.find(id);
|
||||
if(foundInClient != idToObjectMap.end()) {
|
||||
ObjectInfoPtr& o = foundInClient->second;
|
||||
serverSideList.insert(serverSideList.begin() + pos, o);
|
||||
o->syncIgnore = false;
|
||||
sync();
|
||||
|
|
@ -182,6 +212,7 @@ template <typename T, typename IDType> class CollabList {
|
|||
newObj->id = id;
|
||||
newObj->obj = item;
|
||||
newObj->pos = std::min<uint64_t>(pos, clientSideList.size());
|
||||
idToObjectMap.emplace(newObj->id, newObj);
|
||||
item->collabListInfo = newObj;
|
||||
|
||||
serverSideList.insert(serverSideList.begin() + pos, newObj);
|
||||
|
|
@ -207,6 +238,7 @@ template <typename T, typename IDType> class CollabList {
|
|||
std::erase_if(clientSideList, [&](const auto& obj) {
|
||||
if(obj->id == id) {
|
||||
obj->syncIgnore = false;
|
||||
idToObjectMap.erase(obj->id);
|
||||
if(clientEraseCallback)
|
||||
clientEraseCallback(obj);
|
||||
obj->obj->collabListInfo.reset();
|
||||
|
|
@ -216,12 +248,36 @@ template <typename T, typename IDType> class CollabList {
|
|||
});
|
||||
sync();
|
||||
}
|
||||
|
||||
void server_erase_set(const std::unordered_set<ServerClientID>& idsToErase) {
|
||||
std::erase_if(serverSideList, [&](const auto& obj) {
|
||||
if(idsToErase.contains(obj->id)) {
|
||||
obj->syncIgnore = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
std::erase_if(clientSideList, [&](const auto& obj) {
|
||||
if(idsToErase.contains(obj->id)) {
|
||||
obj->syncIgnore = false;
|
||||
if(clientEraseCallback)
|
||||
clientEraseCallback(obj);
|
||||
idToObjectMap.erase(obj->id);
|
||||
obj->obj->collabListInfo.reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
sync();
|
||||
}
|
||||
|
||||
void init_emplace_back(IDType id, const T& item) {
|
||||
auto newObj(std::make_shared<ObjectInfo>());
|
||||
newObj->syncIgnore = false;
|
||||
newObj->id = id;
|
||||
newObj->obj = item;
|
||||
item->collabListInfo = newObj;
|
||||
idToObjectMap.emplace(newObj->id, newObj);
|
||||
|
||||
serverSideList.emplace_back(newObj);
|
||||
clientSideList.emplace_back(newObj);
|
||||
|
|
@ -274,7 +330,9 @@ template <typename T, typename IDType> class CollabList {
|
|||
updateCallback();
|
||||
complete_client_pos_refresh(true);
|
||||
}
|
||||
|
||||
std::function<IDType()> getNewIDFunc;
|
||||
std::vector<ObjectInfoPtr> clientSideList;
|
||||
std::vector<ObjectInfoPtr> serverSideList;
|
||||
std::unordered_map<IDType, ObjectInfoPtr> idToObjectMap;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,11 +8,38 @@
|
|||
#include "../SharedTypes.hpp"
|
||||
#include "../Server/CommandList.hpp"
|
||||
#include <chrono>
|
||||
#include <cereal/types/unordered_set.hpp>
|
||||
|
||||
#ifndef IS_SERVER
|
||||
#include "../MainProgram.hpp"
|
||||
#endif
|
||||
|
||||
void save(cereal::PortableBinaryOutputArchive& a, const CollabListType::ObjectInfo& o) {
|
||||
// Client will send ID, but server should ignore ID and generate its own
|
||||
a(o.pos, o.obj->get_type(), o.id, o.obj->coords, *o.obj);
|
||||
}
|
||||
|
||||
void load(cereal::PortableBinaryInputArchive& a, CollabListType::ObjectInfo& o) {
|
||||
DrawComponentType t;
|
||||
a(o.pos, t, o.id);
|
||||
o.obj = DrawComponent::allocate_comp_type(t);
|
||||
a(o.obj->coords, *o.obj);
|
||||
}
|
||||
|
||||
void SendOrderedComponentVectorOp::save(cereal::PortableBinaryOutputArchive& a) const {
|
||||
a((uint64_t)v->size());
|
||||
for(auto& c : *v)
|
||||
a(*c);
|
||||
}
|
||||
|
||||
void SendOrderedComponentVectorOp::load(cereal::PortableBinaryInputArchive& a) {
|
||||
v->clear();
|
||||
uint64_t vSize;
|
||||
a(vSize);
|
||||
for(uint64_t i = 0; i < vSize; i++)
|
||||
a(*v->emplace_back(std::make_shared<CollabListType::ObjectInfo>()));
|
||||
}
|
||||
|
||||
std::shared_ptr<DrawComponent> DrawComponent::allocate_comp_type(DrawComponentType type) {
|
||||
switch(type) {
|
||||
case DRAWCOMPONENT_BRUSHSTROKE:
|
||||
|
|
@ -29,12 +56,20 @@ std::shared_ptr<DrawComponent> DrawComponent::allocate_comp_type(DrawComponentTy
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void DrawComponent::server_send_place_many(MainServer& server, std::vector<CollabListType::ObjectInfoPtr>& comps) {
|
||||
server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_PLACE_MANY_COMPONENTS, SendOrderedComponentVectorOp{&comps});
|
||||
}
|
||||
|
||||
void DrawComponent::server_send_place(MainServer& server, ServerClientID id, uint64_t placement) {
|
||||
server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_PLACE_COMPONENT, placement, get_type(), id, this->coords, *this);
|
||||
server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_PLACE_SINGLE_COMPONENT, placement, get_type(), id, this->coords, *this);
|
||||
}
|
||||
|
||||
void DrawComponent::server_send_erase(MainServer& server, ServerClientID id) {
|
||||
server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_ERASE_COMPONENT, id);
|
||||
server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_ERASE_SINGLE_COMPONENT, id);
|
||||
}
|
||||
|
||||
void DrawComponent::server_send_erase_set(MainServer& server, const std::unordered_set<ServerClientID>& ids) {
|
||||
server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_ERASE_MANY_COMPONENTS, ids);
|
||||
}
|
||||
|
||||
void DrawComponent::server_send_update_temp(MainServer& server, ServerClientID id) {
|
||||
|
|
@ -48,15 +83,8 @@ void DrawComponent::server_send_update_final(MainServer& server, ServerClientID
|
|||
serverIsTempUpdate = false;
|
||||
}
|
||||
|
||||
void DrawComponent::server_send_transform_temp(MainServer& server, ServerClientID id) {
|
||||
server.netServer->send_items_to_all_clients(UNRELIABLE_COMMAND_CHANNEL, CLIENT_TRANSFORM_COMPONENT, true, id, this->coords);
|
||||
tempServerUpdateTimer = std::chrono::steady_clock::now();
|
||||
serverIsTempUpdate = true;
|
||||
}
|
||||
|
||||
void DrawComponent::server_send_transform_final(MainServer& server, ServerClientID id) {
|
||||
server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_TRANSFORM_COMPONENT, false, id, this->coords);
|
||||
serverIsTempUpdate = false;
|
||||
void DrawComponent::server_send_transform(MainServer& server, ServerClientID id) {
|
||||
server.netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_TRANSFORM_COMPONENT, id, this->coords);
|
||||
}
|
||||
|
||||
void DrawComponent::server_update(MainServer& server, ServerClientID id) {
|
||||
|
|
@ -67,13 +95,6 @@ void DrawComponent::server_update(MainServer& server, ServerClientID id) {
|
|||
serverIsTempUpdate = false;
|
||||
}
|
||||
}
|
||||
if(serverIsTempTransform) {
|
||||
float timeSince = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - tempServerTransformTimer).count();
|
||||
if(timeSince >= 1.0f) {
|
||||
server_send_transform_final(server, id);
|
||||
serverIsTempTransform = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawComponent::get_used_resources(std::unordered_set<ServerClientID>& v) const {
|
||||
|
|
@ -90,14 +111,6 @@ bool DrawComponent::bounds_draw_check(const DrawData& drawData) const {
|
|||
}
|
||||
|
||||
void DrawComponent::check_timers(DrawingProgram& drawP) {
|
||||
if(delayedCoordinateSpace) {
|
||||
float transformDur = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - lastTransformTime).count();
|
||||
if(transformDur > CLIENT_DRAWCOMP_DELAY_TIMER_DURATION) {
|
||||
coords = *delayedCoordinateSpace;
|
||||
delayedCoordinateSpace = nullptr;
|
||||
finalize_update(drawP);
|
||||
}
|
||||
}
|
||||
if(delayedUpdatePtr) {
|
||||
float updateDur = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - lastUpdateTime).count();
|
||||
if(updateDur > CLIENT_DRAWCOMP_DELAY_TIMER_DURATION) {
|
||||
|
|
@ -124,14 +137,13 @@ void DrawComponent::final_update(DrawingProgram& drawP, bool invalidateCache) {
|
|||
finalize_update(drawP, invalidateCache);
|
||||
}
|
||||
|
||||
void DrawComponent::client_send_place(DrawingProgram& drawP) {
|
||||
//if(collabListInfo.lock()) If this fails, then there's a real issue
|
||||
drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_PLACE_COMPONENT, collabListInfo.lock()->pos, get_type(), this->coords, *this);
|
||||
void DrawComponent::client_send_place_many(DrawingProgram& drawP, std::vector<CollabListType::ObjectInfoPtr>& comps) {
|
||||
drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_PLACE_MANY_COMPONENTS, SendOrderedComponentVectorOp{&comps});
|
||||
}
|
||||
|
||||
void DrawComponent::client_send_erase(DrawingProgram& drawP) {
|
||||
if(collabListInfo.lock())
|
||||
drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_ERASE_COMPONENT, collabListInfo.lock()->id);
|
||||
void DrawComponent::client_send_place(DrawingProgram& drawP) {
|
||||
//if(collabListInfo.lock()) If this fails, then there's a real issue
|
||||
drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_PLACE_SINGLE_COMPONENT, collabListInfo.lock()->pos, get_type(), this->coords, *this);
|
||||
}
|
||||
|
||||
void DrawComponent::client_send_update_temp(DrawingProgram& drawP) {
|
||||
|
|
@ -144,14 +156,18 @@ void DrawComponent::client_send_update_final(DrawingProgram& drawP) {
|
|||
drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_UPDATE_COMPONENT, false, collabListInfo.lock()->id, *this);
|
||||
}
|
||||
|
||||
void DrawComponent::client_send_transform_temp(DrawingProgram& drawP) {
|
||||
void DrawComponent::client_send_transform(DrawingProgram& drawP) {
|
||||
if(collabListInfo.lock())
|
||||
drawP.world.con.client_send_items_to_server(UNRELIABLE_COMMAND_CHANNEL, SERVER_TRANSFORM_COMPONENT, true, collabListInfo.lock()->id, this->coords);
|
||||
drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_TRANSFORM_COMPONENT, collabListInfo.lock()->id, this->coords);
|
||||
}
|
||||
|
||||
void DrawComponent::client_send_transform_final(DrawingProgram& drawP) {
|
||||
void DrawComponent::client_send_erase(DrawingProgram& drawP) {
|
||||
if(collabListInfo.lock())
|
||||
drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_TRANSFORM_COMPONENT, false, collabListInfo.lock()->id, this->coords);
|
||||
drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_ERASE_SINGLE_COMPONENT, collabListInfo.lock()->id);
|
||||
}
|
||||
|
||||
void DrawComponent::client_send_erase_set(DrawingProgram& drawP, const std::unordered_set<ServerClientID>& ids) {
|
||||
drawP.world.con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_ERASE_MANY_COMPONENTS, ids);
|
||||
}
|
||||
|
||||
void DrawComponent::finalize_update(DrawingProgram& drawP, bool invalidateCache) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,15 @@ class DrawingProgramCacheBVHNode;
|
|||
|
||||
typedef CollabList<std::shared_ptr<DrawComponent>, ServerClientID> CollabListType;
|
||||
|
||||
void save(cereal::PortableBinaryOutputArchive& a, const CollabListType::ObjectInfo& o);
|
||||
void load(cereal::PortableBinaryInputArchive& a, CollabListType::ObjectInfo& o);
|
||||
|
||||
struct SendOrderedComponentVectorOp {
|
||||
std::vector<CollabListType::ObjectInfoPtr>* v;
|
||||
void save(cereal::PortableBinaryOutputArchive& a) const;
|
||||
void load(cereal::PortableBinaryInputArchive& a);
|
||||
};
|
||||
|
||||
class DrawComponent {
|
||||
public:
|
||||
static std::shared_ptr<DrawComponent> allocate_comp_type(DrawComponentType type);
|
||||
|
|
@ -48,25 +57,23 @@ class DrawComponent {
|
|||
float scale;
|
||||
} transformData;
|
||||
bool shouldDraw = false;
|
||||
unsigned mipmapLevel = 0;
|
||||
uint8_t mipmapLevel = 0;
|
||||
} drawSetupData;
|
||||
|
||||
void canvas_do_calculated_transform(SkCanvas* canvas);
|
||||
void calculate_draw_transform(const DrawData& drawData);
|
||||
|
||||
void server_send_place(MainServer& server, ServerClientID id, uint64_t placement);
|
||||
static void server_send_place_many(MainServer& server, std::vector<CollabListType::ObjectInfoPtr>& comps);
|
||||
static void server_send_erase(MainServer& server, ServerClientID id);
|
||||
static void server_send_erase_set(MainServer& server, const std::unordered_set<ServerClientID>& ids);
|
||||
void server_send_update_temp(MainServer& server, ServerClientID id);
|
||||
void server_send_update_final(MainServer& server, ServerClientID id);
|
||||
void server_send_transform_temp(MainServer& server, ServerClientID id);
|
||||
void server_send_transform_final(MainServer& server, ServerClientID id);
|
||||
void server_send_transform(MainServer& server, ServerClientID id);
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> tempServerUpdateTimer;
|
||||
bool serverIsTempUpdate = false;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> tempServerTransformTimer;
|
||||
bool serverIsTempTransform = false;
|
||||
|
||||
std::weak_ptr<CollabListType::ObjectInfo> collabListInfo;
|
||||
std::weak_ptr<DrawingProgramCacheBVHNode> parentBvhNode;
|
||||
|
||||
|
|
@ -77,17 +84,17 @@ class DrawComponent {
|
|||
std::chrono::time_point<std::chrono::steady_clock> lastUpdateTime;
|
||||
|
||||
std::shared_ptr<DrawComponent> delayedUpdatePtr = nullptr;
|
||||
std::shared_ptr<CoordSpaceHelper> delayedCoordinateSpace = nullptr;
|
||||
|
||||
bool bounds_draw_check(const DrawData& drawData) const;
|
||||
|
||||
void check_timers(DrawingProgram& drawP);
|
||||
static void client_send_place_many(DrawingProgram& drawP, std::vector<CollabListType::ObjectInfoPtr>& comps);
|
||||
void client_send_place(DrawingProgram& drawP);
|
||||
void client_send_erase(DrawingProgram& drawP);
|
||||
static void client_send_erase_set(DrawingProgram& drawP, const std::unordered_set<ServerClientID>& ids);
|
||||
void client_send_update_temp(DrawingProgram& drawP);
|
||||
void client_send_update_final(DrawingProgram& drawP);
|
||||
void client_send_transform_temp(DrawingProgram& drawP);
|
||||
void client_send_transform_final(DrawingProgram& drawP);
|
||||
void client_send_transform(DrawingProgram& drawP);
|
||||
|
||||
std::optional<SCollision::AABB<WorldScalar>> worldAABB;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "../MainProgram.hpp"
|
||||
#include <Helpers/Logger.hpp>
|
||||
#include <Helpers/Parallel.hpp>
|
||||
#include <cereal/types/unordered_set.hpp>
|
||||
|
||||
DrawingProgram::DrawingProgram(World& initWorld):
|
||||
world(initWorld),
|
||||
|
|
@ -52,15 +53,9 @@ DrawingProgram::DrawingProgram(World& initWorld):
|
|||
};
|
||||
components.clientEraseCallback = [&](const CollabListType::ObjectInfoPtr& c) {
|
||||
compCache.erase_component(c);
|
||||
delayedUpdateTransformComponents.erase(c->obj);
|
||||
delayedUpdateComponents.erase(c->obj);
|
||||
updateableComponents.erase(c->obj);
|
||||
};
|
||||
components.clientEraseSetCallback = [&](const std::unordered_set<CollabListType::ObjectInfoPtr>& comps) {
|
||||
for(auto& c : comps) {
|
||||
delayedUpdateTransformComponents.erase(c->obj);
|
||||
updateableComponents.erase(c->obj);
|
||||
}
|
||||
};
|
||||
components.clientInsertOrderedVectorCallback = [&](const std::vector<CollabListType::ObjectInfoPtr>& comps) {
|
||||
for(auto& c : comps)
|
||||
components.clientInsertCallback(c);
|
||||
|
|
@ -75,10 +70,10 @@ void DrawingProgram::init_client_callbacks() {
|
|||
bool isTemp;
|
||||
ServerClientID id;
|
||||
message(isTemp, id);
|
||||
std::shared_ptr<DrawComponent>* compPtr = components.get_item_by_id(id);
|
||||
if(!compPtr)
|
||||
auto objPtr = components.get_item_by_id(id);
|
||||
if(!objPtr)
|
||||
return;
|
||||
std::shared_ptr<DrawComponent>& comp = *compPtr;
|
||||
std::shared_ptr<DrawComponent>& comp = objPtr->obj;
|
||||
float dur = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - comp->lastUpdateTime).count();
|
||||
if(dur > CLIENT_DRAWCOMP_DELAY_TIMER_DURATION){
|
||||
comp->delayedUpdatePtr = nullptr;
|
||||
|
|
@ -91,31 +86,22 @@ void DrawingProgram::init_client_callbacks() {
|
|||
else {
|
||||
comp->delayedUpdatePtr = DrawComponent::allocate_comp_type(comp->get_type());
|
||||
message(*comp->delayedUpdatePtr);
|
||||
delayedUpdateTransformComponents.emplace(comp);
|
||||
delayedUpdateComponents.emplace(comp);
|
||||
}
|
||||
});
|
||||
world.con.client_add_recv_callback(CLIENT_TRANSFORM_COMPONENT, [&](cereal::PortableBinaryInputArchive& message) {
|
||||
bool isTemp;
|
||||
ServerClientID id;
|
||||
message(isTemp, id);
|
||||
std::shared_ptr<DrawComponent>* compPtr = components.get_item_by_id(id);
|
||||
if(!compPtr)
|
||||
message(id);
|
||||
auto objPtr = components.get_item_by_id(id);
|
||||
if(!objPtr)
|
||||
return;
|
||||
std::shared_ptr<DrawComponent>& comp = *compPtr;
|
||||
float dur = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - comp->lastTransformTime).count();
|
||||
if(dur > CLIENT_DRAWCOMP_DELAY_TIMER_DURATION){
|
||||
comp->delayedCoordinateSpace = nullptr;
|
||||
message(comp->coords);
|
||||
if(!isTemp)
|
||||
comp->finalize_update(*this); // No need to update draw data during transformation
|
||||
}
|
||||
else {
|
||||
comp->delayedCoordinateSpace = std::make_shared<CoordSpaceHelper>();
|
||||
message(*comp->delayedCoordinateSpace);
|
||||
delayedUpdateTransformComponents.emplace(comp);
|
||||
}
|
||||
if(selection.is_selected(objPtr)) // Whatever transformation we're doing right now will overwrite this transformation, so we can ignore this message
|
||||
return;
|
||||
std::shared_ptr<DrawComponent>& comp = objPtr->obj;
|
||||
message(comp->coords);
|
||||
comp->finalize_update(*this); // No need to update draw data during transformation
|
||||
});
|
||||
world.con.client_add_recv_callback(CLIENT_PLACE_COMPONENT, [&](cereal::PortableBinaryInputArchive& message) {
|
||||
world.con.client_add_recv_callback(CLIENT_PLACE_SINGLE_COMPONENT, [&](cereal::PortableBinaryInputArchive& message) {
|
||||
uint64_t insertPosition;
|
||||
DrawComponentType type;
|
||||
message(insertPosition, type);
|
||||
|
|
@ -126,17 +112,42 @@ void DrawingProgram::init_client_callbacks() {
|
|||
if(didntExistPreviously)
|
||||
newObj->final_update(*this);
|
||||
});
|
||||
world.con.client_add_recv_callback(CLIENT_ERASE_COMPONENT, [&](cereal::PortableBinaryInputArchive& message) {
|
||||
ServerClientID cToRemove;
|
||||
message(cToRemove);
|
||||
components.server_erase(cToRemove);
|
||||
world.con.client_add_recv_callback(CLIENT_PLACE_MANY_COMPONENTS, [&](cereal::PortableBinaryInputArchive& message) {
|
||||
std::vector<CollabListType::ObjectInfoPtr> sortedPlacedComponents;
|
||||
|
||||
SendOrderedComponentVectorOp a{&sortedPlacedComponents};
|
||||
message(a);
|
||||
|
||||
std::vector<bool> didntExistPreviously = components.server_insert_ordered_vector(sortedPlacedComponents);
|
||||
if(sortedPlacedComponents.size() >= DrawingProgramCache::MINIMUM_COMPONENTS_TO_START_REBUILD) {
|
||||
parallel_loop_container(sortedPlacedComponents, [&](const auto& c){
|
||||
c->obj->final_update(*this, false);
|
||||
});
|
||||
force_rebuild_cache();
|
||||
}
|
||||
else {
|
||||
for(size_t i = 0; i < sortedPlacedComponents.size(); i++) {
|
||||
if(didntExistPreviously[i])
|
||||
sortedPlacedComponents[i]->obj->final_update(*this);
|
||||
}
|
||||
}
|
||||
});
|
||||
world.con.client_add_recv_callback(CLIENT_ERASE_SINGLE_COMPONENT, [&](cereal::PortableBinaryInputArchive& message) {
|
||||
ServerClientID idToErase;
|
||||
message(idToErase);
|
||||
components.server_erase(idToErase);
|
||||
});
|
||||
world.con.client_add_recv_callback(CLIENT_ERASE_MANY_COMPONENTS, [&](cereal::PortableBinaryInputArchive& message) {
|
||||
std::unordered_set<ServerClientID> idsToErase;
|
||||
message(idsToErase);
|
||||
components.server_erase_set(idsToErase);
|
||||
});
|
||||
}
|
||||
|
||||
void DrawingProgram::check_delayed_update_transform_timers() {
|
||||
std::erase_if(delayedUpdateTransformComponents, [&](auto& comp) {
|
||||
void DrawingProgram::check_delayed_update_timers() {
|
||||
std::erase_if(delayedUpdateComponents, [&](auto& comp) {
|
||||
comp->check_timers(*this);
|
||||
return !comp->delayedUpdatePtr && !comp->delayedCoordinateSpace;
|
||||
return !comp->delayedUpdatePtr;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -352,11 +363,26 @@ void DrawingProgram::update() {
|
|||
if(controls.leftClickReleased)
|
||||
controls.leftClickReleased = false;
|
||||
|
||||
check_delayed_update_transform_timers();
|
||||
check_delayed_update_timers();
|
||||
check_updateable_components();
|
||||
|
||||
compCache.update();
|
||||
selection.update();
|
||||
|
||||
if(controls.selectedTool == TOOL_ERASER)
|
||||
compCache.test_rebuild_dont_include_set_dont_include_nodes(components.client_list(), eraserTool.erasedComponents, eraserTool.erasedBVHNodes);
|
||||
else if(controls.selectedTool == TOOL_RECTSELECT)
|
||||
compCache.test_rebuild_dont_include_set(components.client_list(), selection.get_selected_set());
|
||||
else
|
||||
compCache.test_rebuild(components.client_list());
|
||||
}
|
||||
|
||||
void DrawingProgram::force_rebuild_cache() {
|
||||
if(controls.selectedTool == TOOL_ERASER)
|
||||
compCache.test_rebuild_dont_include_set_dont_include_nodes(components.client_list(), eraserTool.erasedComponents, eraserTool.erasedBVHNodes, true);
|
||||
else if(controls.selectedTool == TOOL_RECTSELECT)
|
||||
compCache.test_rebuild_dont_include_set(components.client_list(), selection.get_selected_set(), true);
|
||||
else
|
||||
compCache.test_rebuild(components.client_list(), true);
|
||||
}
|
||||
|
||||
void DrawingProgram::drag_drop_update() {
|
||||
|
|
@ -448,7 +474,7 @@ void DrawingProgram::initialize_draw_data(cereal::PortableBinaryInputArchive& a)
|
|||
parallel_loop_all_components([&](const auto& c){
|
||||
c->obj->final_update(*this, false);
|
||||
});
|
||||
compCache.force_rebuild(components.client_list());
|
||||
compCache.test_rebuild(components.client_list(), true);
|
||||
}
|
||||
|
||||
void DrawingProgram::add_undo_place_component(uint64_t placement, const std::shared_ptr<DrawComponent>& comp) {
|
||||
|
|
@ -476,15 +502,17 @@ void DrawingProgram::add_undo_place_components(uint64_t placement, const std::ve
|
|||
world.undo.push(UndoManager::UndoRedoPair{
|
||||
[&, comps]() {
|
||||
bool toRet = true;
|
||||
std::unordered_set<ServerClientID> idsToErase;
|
||||
for(auto& c : comps) {
|
||||
if(!c->collabListInfo.lock())
|
||||
toRet = false;
|
||||
else {
|
||||
idsToErase.emplace(c->collabListInfo.lock()->id);
|
||||
ServerClientID compID;
|
||||
c->client_send_erase(*this);
|
||||
components.client_erase(c, compID);
|
||||
}
|
||||
}
|
||||
DrawComponent::client_send_erase_set(*this, idsToErase);
|
||||
reset_tools();
|
||||
return toRet;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -55,14 +55,16 @@ class DrawingProgram {
|
|||
CollabListType components;
|
||||
|
||||
std::unordered_set<std::shared_ptr<DrawComponent>> updateableComponents;
|
||||
std::unordered_set<std::shared_ptr<DrawComponent>> delayedUpdateTransformComponents;
|
||||
std::unordered_set<std::shared_ptr<DrawComponent>> delayedUpdateComponents;
|
||||
|
||||
Vector4f* get_foreground_color_ptr();
|
||||
private:
|
||||
|
||||
void check_delayed_update_transform_timers();
|
||||
void check_delayed_update_timers();
|
||||
void check_updateable_components();
|
||||
|
||||
void force_rebuild_cache();
|
||||
|
||||
std::atomic<bool> addFileInNextFrame = false;
|
||||
std::pair<std::string, Vector2f> addFileInfo;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,9 +49,45 @@ void DrawingProgramCache::clear_own_cached_surfaces() {
|
|||
});
|
||||
}
|
||||
|
||||
void DrawingProgramCache::update() {
|
||||
if(!disableRefresh && unsortedComponents.size() >= 1000 && (std::chrono::steady_clock::now() - lastBvhBuildTime) >= std::chrono::seconds(5))
|
||||
force_rebuild(drawP.components.client_list());
|
||||
bool DrawingProgramCache::check_if_rebuild_should_occur() {
|
||||
return (unsortedComponents.size() >= MINIMUM_COMPONENTS_TO_START_REBUILD && (std::chrono::steady_clock::now() - lastBvhBuildTime) >= std::chrono::seconds(5));
|
||||
}
|
||||
|
||||
void DrawingProgramCache::test_rebuild(const std::vector<CollabListType::ObjectInfoPtr>& comps, bool force) {
|
||||
if(force || check_if_rebuild_should_occur())
|
||||
force_rebuild(comps);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::test_rebuild_dont_include_set(const std::vector<CollabListType::ObjectInfoPtr>& comps, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude, bool force) {
|
||||
if(force || check_if_rebuild_should_occur())
|
||||
force_rebuild_dont_include_objs(comps, objsToNotInclude);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::test_rebuild_dont_include_set_dont_include_nodes(const std::vector<CollabListType::ObjectInfoPtr>& comps, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& nodesToNotInclude, bool force) {
|
||||
if(force || check_if_rebuild_should_occur()) {
|
||||
auto objsToNotIncludeNew = objsToNotInclude;
|
||||
move_components_from_bvh_nodes_to_set(objsToNotIncludeNew, nodesToNotInclude);
|
||||
force_rebuild_dont_include_objs(comps, objsToNotIncludeNew);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawingProgramCache::move_components_from_bvh_nodes_to_set(std::unordered_set<CollabListType::ObjectInfoPtr>& s, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& bvhNodes) {
|
||||
for(auto& b : bvhNodes)
|
||||
move_components_from_bvh_node_to_set(s, b);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::move_components_from_bvh_node_to_set(std::unordered_set<CollabListType::ObjectInfoPtr>& s, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode) {
|
||||
for(auto& c : bvhNode->components)
|
||||
s.emplace(c);
|
||||
for(auto& p : bvhNode->children)
|
||||
move_components_from_bvh_node_to_set(s, p);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::force_rebuild_dont_include_objs(std::vector<CollabListType::ObjectInfoPtr> componentsToBuild, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude) {
|
||||
std::erase_if(componentsToBuild, [&objsToNotInclude](auto& c) {
|
||||
return objsToNotInclude.contains(c);
|
||||
});
|
||||
build(componentsToBuild);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::force_rebuild(const std::vector<CollabListType::ObjectInfoPtr>& componentsToBuild) {
|
||||
|
|
@ -151,7 +187,7 @@ void DrawingProgramCache::build_bvh_node(const std::shared_ptr<DrawingProgramCac
|
|||
|
||||
build_bvh_node_coords_and_resolution(*bvhNode);
|
||||
|
||||
if(components.size() < 100) {
|
||||
if(components.size() < MAXIMUM_COMPONENTS_IN_SINGLE_NODE) {
|
||||
bvhNode->components = components;
|
||||
for(auto& c : bvhNode->components)
|
||||
c->obj->parentBvhNode = bvhNode;
|
||||
|
|
|
|||
|
|
@ -33,16 +33,24 @@ class DrawingProgramCache {
|
|||
DrawingProgramCache(DrawingProgram& initDrawP);
|
||||
~DrawingProgramCache();
|
||||
|
||||
static std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>> nodesWithCachedSurfaces;
|
||||
bool disableRefresh = false;
|
||||
static constexpr size_t MINIMUM_COMPONENTS_TO_START_REBUILD = 1000;
|
||||
static constexpr size_t MAXIMUM_COMPONENTS_IN_SINGLE_NODE = 100;
|
||||
|
||||
static std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>> nodesWithCachedSurfaces;
|
||||
|
||||
bool check_if_rebuild_should_occur();
|
||||
void test_rebuild(const std::vector<CollabListType::ObjectInfoPtr>& comps, bool force = false);
|
||||
void test_rebuild_dont_include_set(const std::vector<CollabListType::ObjectInfoPtr>& comps, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude, bool force = false);
|
||||
void test_rebuild_dont_include_set_dont_include_nodes(const std::vector<CollabListType::ObjectInfoPtr>& comps, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& nodesToNotInclude, bool force = false);
|
||||
|
||||
static void move_components_from_bvh_nodes_to_set(std::unordered_set<CollabListType::ObjectInfoPtr>& s, const std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>>& bvhNodes);
|
||||
static void move_components_from_bvh_node_to_set(std::unordered_set<CollabListType::ObjectInfoPtr>& s, const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode);
|
||||
|
||||
void update();
|
||||
void erase_component(const CollabListType::ObjectInfoPtr& c);
|
||||
void add_component(const CollabListType::ObjectInfoPtr& c);
|
||||
void refresh_all_draw_cache(const DrawData& drawData);
|
||||
void traverse_bvh_run_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, const std::vector<CollabListType::ObjectInfoPtr>& components)> f);
|
||||
void traverse_bvh_erase_function(const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CollabListType::ObjectInfoPtr>& components)> f);
|
||||
void force_rebuild(const std::vector<CollabListType::ObjectInfoPtr>& componentsToBuild);
|
||||
// Run before actually updating the component
|
||||
void preupdate_component(const CollabListType::ObjectInfoPtr& c);
|
||||
void invalidate_cache_before_pos(uint64_t placementToInvalidateAt);
|
||||
|
|
@ -53,6 +61,9 @@ class DrawingProgramCache {
|
|||
const std::chrono::steady_clock::time_point& get_last_bvh_build_time() const;
|
||||
void clear_own_cached_surfaces();
|
||||
private:
|
||||
void force_rebuild_dont_include_objs(std::vector<CollabListType::ObjectInfoPtr> componentsToBuild, const std::unordered_set<CollabListType::ObjectInfoPtr>& objsToNotInclude);
|
||||
void force_rebuild(const std::vector<CollabListType::ObjectInfoPtr>& componentsToBuild);
|
||||
|
||||
bool traverse_bvh_erase_function_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const SCollision::AABB<WorldScalar>& aabb, std::function<bool(const std::shared_ptr<DrawingProgramCacheBVHNode>& node, std::vector<CollabListType::ObjectInfoPtr>& components)> f);
|
||||
void build_bvh_node_coords_and_resolution(DrawingProgramCacheBVHNode& node);
|
||||
void refresh_draw_cache(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, const DrawData& drawData);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP):
|
|||
drawP(initDrawP)
|
||||
{}
|
||||
|
||||
const std::unordered_set<CollabListType::ObjectInfoPtr>& DrawingProgramSelection::get_selected_set() {
|
||||
return selectedSet;
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection<float>& cC) {
|
||||
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
|
||||
|
||||
|
|
@ -73,19 +77,26 @@ void DrawingProgramSelection::deselect_all() {
|
|||
parallel_loop_container(a, [&](auto& obj) {
|
||||
obj->obj->coords = selectionTransformCoords.other_coord_space_from_this_space(obj->obj->coords);
|
||||
obj->obj->final_update(drawP, false);
|
||||
obj->obj->client_send_transform(drawP);
|
||||
});
|
||||
selectedSet.clear();
|
||||
cache.clear();
|
||||
selectionTransformCoords = CoordSpaceHelper();
|
||||
drawP.compCache.force_rebuild(drawP.components.client_list());
|
||||
drawP.force_rebuild_cache();
|
||||
transformOpHappening = TransformOperation::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawingProgramSelection::is_selected(const CollabListType::ObjectInfoPtr& objToCheck) {
|
||||
return selectedSet.contains(objToCheck);
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::update() {
|
||||
if(is_something_selected()) {
|
||||
if(cache.get_unsorted_component_list().size() >= 1000 && (std::chrono::steady_clock::now() - cache.get_last_bvh_build_time()) >= std::chrono::seconds(5))
|
||||
cache.force_rebuild(std::vector<CollabListType::ObjectInfoPtr>(selectedSet.begin(), selectedSet.end()));
|
||||
|
||||
if(cache.check_if_rebuild_should_occur())
|
||||
cache.test_rebuild(std::vector<CollabListType::ObjectInfoPtr>(selectedSet.begin(), selectedSet.end()), true);
|
||||
|
||||
if(drawP.world.main.input.key(InputManager::KEY_DRAW_UNSELECT).pressed)
|
||||
deselect_all();
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ class DrawingProgramSelection {
|
|||
void draw_gui(SkCanvas* canvas, const DrawData& drawData);
|
||||
bool is_something_selected();
|
||||
bool mouse_collided_with_selection();
|
||||
bool is_selected(const CollabListType::ObjectInfoPtr& objToCheck);
|
||||
const std::unordered_set<CollabListType::ObjectInfoPtr>& get_selected_set();
|
||||
private:
|
||||
bool mouse_collided_with_selection_aabb();
|
||||
bool mouse_collided_with_scale_point();
|
||||
|
|
|
|||
|
|
@ -22,16 +22,17 @@ void EraserTool::gui_toolbox() {
|
|||
|
||||
void EraserTool::reset_tool() {
|
||||
if(!erasedComponents.empty()) {
|
||||
for(auto& bvhNode : erasedBVHNodes)
|
||||
move_erased_components_from_bvh_nodes_recursive(bvhNode);
|
||||
DrawingProgramCache::move_components_from_bvh_nodes_to_set(erasedComponents, erasedBVHNodes);
|
||||
|
||||
std::unordered_set<ServerClientID> idsToErase;
|
||||
for(auto& c : erasedComponents)
|
||||
c->obj->client_send_erase(drawP);
|
||||
idsToErase.emplace(c->id);
|
||||
DrawComponent::client_send_erase_set(drawP, idsToErase);
|
||||
drawP.components.client_erase_set(erasedComponents);
|
||||
|
||||
drawP.world.undo.push(UndoManager::UndoRedoPair{
|
||||
[&, erasedCompVal = erasedComponents]() {
|
||||
std::vector<CollabListType::ObjectInfoPtr> sortedObjects(erasedCompVal.begin(), erasedCompVal.end());
|
||||
[&, erasedComponents = erasedComponents]() {
|
||||
std::vector<CollabListType::ObjectInfoPtr> sortedObjects(erasedComponents.begin(), erasedComponents.end());
|
||||
std::sort(sortedObjects.begin(), sortedObjects.end(), [](auto& a, auto& b) {
|
||||
return a->pos < b->pos;
|
||||
});
|
||||
|
|
@ -41,27 +42,27 @@ void EraserTool::reset_tool() {
|
|||
return false;
|
||||
|
||||
drawP.components.client_insert_ordered_vector(sortedObjects);
|
||||
|
||||
for(auto& comp : sortedObjects)
|
||||
comp->obj->client_send_place(drawP);
|
||||
DrawComponent::client_send_place_many(drawP, sortedObjects);
|
||||
|
||||
drawP.reset_tools();
|
||||
|
||||
return true;
|
||||
},
|
||||
[&, erasedCompVal = erasedComponents]() {
|
||||
for(auto& comp : erasedCompVal)
|
||||
[&, erasedComponents = erasedComponents]() {
|
||||
for(auto& comp : erasedComponents)
|
||||
if(!comp->obj->collabListInfo.lock())
|
||||
return false;
|
||||
|
||||
for(auto& comp : erasedCompVal)
|
||||
comp->obj->client_send_erase(drawP);
|
||||
std::unordered_set<ServerClientID> idsToErase;
|
||||
for(auto& c : erasedComponents)
|
||||
idsToErase.emplace(c->id);
|
||||
|
||||
drawP.components.client_erase_set(erasedCompVal);
|
||||
DrawComponent::client_send_erase_set(drawP, idsToErase);
|
||||
drawP.components.client_erase_set(erasedComponents);
|
||||
|
||||
drawP.reset_tools();
|
||||
|
||||
drawP.compCache.force_rebuild(drawP.components.client_list());
|
||||
drawP.force_rebuild_cache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -69,7 +70,6 @@ void EraserTool::reset_tool() {
|
|||
}
|
||||
erasedComponents.clear();
|
||||
erasedBVHNodes.clear();
|
||||
drawP.compCache.disableRefresh = false;
|
||||
}
|
||||
|
||||
void EraserTool::tool_update() {
|
||||
|
|
@ -82,8 +82,6 @@ void EraserTool::tool_update() {
|
|||
SCollision::generate_wide_line(cC, prevMousePos, drawP.world.main.input.mouse.pos, drawP.controls.relativeWidth * 2.0f, true);
|
||||
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
|
||||
|
||||
drawP.compCache.disableRefresh = true;
|
||||
|
||||
drawP.compCache.traverse_bvh_erase_function(cCWorld.bounds, [&](const auto& bvhNode, auto& comps) {
|
||||
if(bvhNode &&
|
||||
SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.min)) &&
|
||||
|
|
@ -109,13 +107,6 @@ void EraserTool::tool_update() {
|
|||
reset_tool();
|
||||
}
|
||||
|
||||
void EraserTool::move_erased_components_from_bvh_nodes_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode) {
|
||||
for(auto& c : bvhNode->components)
|
||||
erasedComponents.emplace(c);
|
||||
for(auto& p : bvhNode->children)
|
||||
move_erased_components_from_bvh_nodes_recursive(p);
|
||||
}
|
||||
|
||||
void EraserTool::draw(SkCanvas* canvas, const DrawData& drawData) {
|
||||
if(!drawData.main->toolbar.io->hoverObstructed) {
|
||||
SkColor4f c = drawP.world.main.canvasTheme.toolFrontColor;
|
||||
|
|
|
|||
|
|
@ -12,11 +12,10 @@ class EraserTool {
|
|||
void tool_update();
|
||||
void reset_tool();
|
||||
void draw(SkCanvas* canvas, const DrawData& drawData);
|
||||
private:
|
||||
|
||||
std::unordered_set<CollabListType::ObjectInfoPtr> erasedComponents;
|
||||
std::unordered_set<std::shared_ptr<DrawingProgramCacheBVHNode>> erasedBVHNodes;
|
||||
|
||||
void move_erased_components_from_bvh_nodes_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode);
|
||||
private:
|
||||
|
||||
DrawingProgram& drawP;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,13 +35,11 @@ void RectSelectTool::gui_toolbox() {
|
|||
void RectSelectTool::reset_tool() {
|
||||
drawP.selection.deselect_all();
|
||||
controls = RectSelectControls();
|
||||
drawP.compCache.disableRefresh = false;
|
||||
}
|
||||
|
||||
void RectSelectTool::tool_update() {
|
||||
switch(controls.selectionMode) {
|
||||
case 0: {
|
||||
drawP.compCache.disableRefresh = false;
|
||||
if(drawP.controls.leftClick) {
|
||||
if(drawP.selection.is_something_selected()) {
|
||||
if(!drawP.selection.mouse_collided_with_selection())
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ enum ServerCommands : MessageCommandType {
|
|||
SERVER_KEEP_ALIVE,
|
||||
SERVER_INITIAL_DATA,
|
||||
SERVER_MOVE_MOUSE,
|
||||
SERVER_PLACE_COMPONENT,
|
||||
SERVER_PLACE_SINGLE_COMPONENT,
|
||||
SERVER_PLACE_MANY_COMPONENTS,
|
||||
SERVER_TRANSFORM_COMPONENT,
|
||||
SERVER_ERASE_COMPONENT,
|
||||
SERVER_ERASE_SINGLE_COMPONENT,
|
||||
SERVER_ERASE_MANY_COMPONENTS,
|
||||
SERVER_UPDATE_COMPONENT,
|
||||
SERVER_RESOURCE_INIT,
|
||||
SERVER_RESOURCE_DATA,
|
||||
|
|
@ -24,9 +26,11 @@ enum ClientCommands : MessageCommandType {
|
|||
CLIENT_INITIAL_DATA,
|
||||
CLIENT_USER_CONNECT,
|
||||
CLIENT_USER_DISCONNECT,
|
||||
CLIENT_PLACE_COMPONENT,
|
||||
CLIENT_PLACE_SINGLE_COMPONENT,
|
||||
CLIENT_PLACE_MANY_COMPONENTS,
|
||||
CLIENT_TRANSFORM_COMPONENT,
|
||||
CLIENT_ERASE_COMPONENT,
|
||||
CLIENT_ERASE_SINGLE_COMPONENT,
|
||||
CLIENT_ERASE_MANY_COMPONENTS,
|
||||
CLIENT_UPDATE_COMPONENT,
|
||||
CLIENT_MOVE_MOUSE,
|
||||
CLIENT_NEW_RESOURCE,
|
||||
|
|
@ -35,5 +39,6 @@ enum ClientCommands : MessageCommandType {
|
|||
CLIENT_REMOVE_BOOKMARK
|
||||
};
|
||||
|
||||
// NOTE: Change these values whenever savefile is incompatible with previous version
|
||||
#define SAVEFILE_HEADER_LEN 12
|
||||
#define SAVEFILE_HEADER "INFPNT000001"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <cereal/types/unordered_map.hpp>
|
||||
#include <cereal/types/utility.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
#include <cereal/types/unordered_set.hpp>
|
||||
#include <Helpers/Serializers.hpp>
|
||||
#include <Helpers/Random.hpp>
|
||||
#include <chrono>
|
||||
|
|
@ -40,6 +41,7 @@ void ServerData::load(cereal::PortableBinaryInputArchive& a) {
|
|||
auto newComp = DrawComponent::allocate_comp_type(t);
|
||||
a(newComp->coords, *newComp);
|
||||
components.emplace_back(id, newComp);
|
||||
idToComponentMap.emplace(id, newComp);
|
||||
}
|
||||
a(bookmarks);
|
||||
}
|
||||
|
|
@ -60,8 +62,10 @@ ClientPortionID ServerData::get_max_id(ServerPortionID serverID) const {
|
|||
MainServer::MainServer(World& initWorld, const std::string& serverLocalID):
|
||||
world(initWorld)
|
||||
{
|
||||
for(auto& c : world.drawProg.components.client_list())
|
||||
for(auto& c : world.drawProg.components.client_list()) {
|
||||
data.components.emplace_back(c->id, c->obj->copy());
|
||||
data.idToComponentMap.emplace(data.components.back().first, data.components.back().second);
|
||||
}
|
||||
data.bookmarks = world.bMan.bookmark_list();
|
||||
data.resources = world.rMan.resource_list();
|
||||
|
||||
|
|
@ -102,7 +106,7 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID):
|
|||
message(c.camCoords, c.windowSize, c.cursorPos);
|
||||
netServer->send_items_to_all_clients_except(client, UNRELIABLE_COMMAND_CHANNEL, CLIENT_MOVE_MOUSE, c.id.first, c.camCoords, c.windowSize, c.cursorPos);
|
||||
});
|
||||
netServer->add_recv_callback(SERVER_PLACE_COMPONENT, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
|
||||
netServer->add_recv_callback(SERVER_PLACE_SINGLE_COMPONENT, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
|
||||
uint64_t placement;
|
||||
DrawComponentType type;
|
||||
message(placement, type);
|
||||
|
|
@ -111,39 +115,93 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID):
|
|||
ServerClientID id = clients[client->customID].get_next_id();
|
||||
placement = std::min<uint64_t>(placement, data.components.size());
|
||||
data.components.insert(data.components.begin() + placement, {id, newComp});
|
||||
data.idToComponentMap.emplace(id, newComp);
|
||||
newComp->server_send_place(*this, id, placement);
|
||||
});
|
||||
netServer->add_recv_callback(SERVER_ERASE_COMPONENT, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
|
||||
netServer->add_recv_callback(SERVER_PLACE_MANY_COMPONENTS, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
|
||||
auto& cli = clients[client->customID];
|
||||
|
||||
std::vector<CollabListType::ObjectInfoPtr> objOrderedVector;
|
||||
SendOrderedComponentVectorOp a{&objOrderedVector};
|
||||
message(a);
|
||||
|
||||
std::vector<std::pair<ServerClientID, std::shared_ptr<DrawComponent>>> objOrderedComponentPairs;
|
||||
for(auto& o : objOrderedVector) {
|
||||
o->id = cli.get_next_id();
|
||||
objOrderedComponentPairs.emplace_back(o->id, o->obj);
|
||||
}
|
||||
|
||||
uint64_t startPoint = 0;
|
||||
|
||||
if(objOrderedVector.empty())
|
||||
return;
|
||||
|
||||
data.idToComponentMap.emplace(objOrderedVector.front()->id, objOrderedVector.front()->obj);
|
||||
|
||||
for(uint64_t i = 1; i < static_cast<uint64_t>(objOrderedVector.size()); i++) {
|
||||
auto& obj = objOrderedVector[i];
|
||||
data.idToComponentMap.emplace(obj->id, obj->obj);
|
||||
if(obj->pos - objOrderedVector[startPoint]->pos != (i - startPoint)) {
|
||||
uint64_t insertPosition = std::min(data.components.size(), objOrderedVector[startPoint]->pos);
|
||||
data.components.insert(data.components.begin() + insertPosition, objOrderedComponentPairs.begin() + startPoint, objOrderedComponentPairs.begin() + i);
|
||||
startPoint = i;
|
||||
}
|
||||
}
|
||||
|
||||
data.components.insert(data.components.begin() + std::min(data.components.size(), objOrderedVector[startPoint]->pos), objOrderedComponentPairs.begin() + startPoint, objOrderedComponentPairs.end());
|
||||
|
||||
startPoint = 0;
|
||||
|
||||
for(uint64_t i = 0; i < data.components.size(); i++) {
|
||||
if(startPoint >= objOrderedVector.size())
|
||||
break;
|
||||
auto& [id, c] = data.components[i];
|
||||
auto& o = objOrderedVector[startPoint];
|
||||
if(c == o->obj) {
|
||||
o->id = id;
|
||||
o->pos = i;
|
||||
startPoint++;
|
||||
}
|
||||
}
|
||||
|
||||
DrawComponent::server_send_place_many(*this, objOrderedVector);
|
||||
});
|
||||
netServer->add_recv_callback(SERVER_ERASE_SINGLE_COMPONENT, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
|
||||
ServerClientID compToRemove;
|
||||
message(compToRemove);
|
||||
std::erase_if(data.components, [&](auto& c){ return c.first == compToRemove; });
|
||||
DrawComponent::server_send_erase(*this, compToRemove);
|
||||
data.idToComponentMap.erase(compToRemove);
|
||||
std::erase_if(data.components, [&](auto& p) {
|
||||
return p.first == compToRemove;
|
||||
});
|
||||
});
|
||||
netServer->add_recv_callback(SERVER_ERASE_MANY_COMPONENTS, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
|
||||
std::unordered_set<ServerClientID> idsToRemove;
|
||||
message(idsToRemove);
|
||||
DrawComponent::server_send_erase_set(*this, idsToRemove);
|
||||
for(auto& id : idsToRemove)
|
||||
data.idToComponentMap.erase(id);
|
||||
std::erase_if(data.components, [&](auto& p) {
|
||||
return idsToRemove.contains(p.first);
|
||||
});
|
||||
});
|
||||
netServer->add_recv_callback(SERVER_TRANSFORM_COMPONENT, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
|
||||
bool isTemp;
|
||||
ServerClientID idToTransform;
|
||||
message(isTemp, idToTransform);
|
||||
auto a = std::find_if(data.components.begin(), data.components.end(), [&](auto& c) {
|
||||
return (c.first == idToTransform);
|
||||
});
|
||||
if(a != data.components.end()) {
|
||||
std::shared_ptr<DrawComponent>& comp = (*a).second;
|
||||
message(idToTransform);
|
||||
auto it = data.idToComponentMap.find(idToTransform);
|
||||
if(it != data.idToComponentMap.end()) {
|
||||
std::shared_ptr<DrawComponent>& comp = it->second;
|
||||
message(comp->coords);
|
||||
if(isTemp)
|
||||
comp->server_send_transform_temp(*this, idToTransform);
|
||||
else
|
||||
comp->server_send_transform_final(*this, idToTransform);
|
||||
comp->server_send_transform(*this, idToTransform);
|
||||
}
|
||||
});
|
||||
netServer->add_recv_callback(SERVER_UPDATE_COMPONENT, [&](std::shared_ptr<NetServer::ClientData> client, cereal::PortableBinaryInputArchive& message) {
|
||||
bool isTemp;
|
||||
ServerClientID idToTransform;
|
||||
message(isTemp, idToTransform);
|
||||
auto a = std::find_if(data.components.begin(), data.components.end(), [&](auto& c) {
|
||||
return (c.first == idToTransform);
|
||||
});
|
||||
if(a != data.components.end()) {
|
||||
std::shared_ptr<DrawComponent>& comp = (*a).second;
|
||||
auto it = data.idToComponentMap.find(idToTransform);
|
||||
if(it != data.idToComponentMap.end()) {
|
||||
std::shared_ptr<DrawComponent>& comp = it->second;
|
||||
message(*comp);
|
||||
if(isTemp)
|
||||
comp->server_send_update_temp(*this, idToTransform);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ class DrawComponent;
|
|||
class ServerData {
|
||||
public:
|
||||
std::vector<std::pair<ServerClientID, std::shared_ptr<DrawComponent>>> components;
|
||||
std::unordered_map<ServerClientID, std::shared_ptr<DrawComponent>> idToComponentMap;
|
||||
std::unordered_map<ServerClientID, ResourceData> resources;
|
||||
std::unordered_map<std::string, Bookmark> bookmarks;
|
||||
void save(cereal::PortableBinaryOutputArchive& a) const;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue