Add character swapping (no GUI yet)
This commit is contained in:
parent
4fbd67dacc
commit
cb19eef701
@ -506,9 +506,17 @@ void ClientApplication::changeState(MainAppState newState) {
|
|||||||
m_playerStorage = make_shared<PlayerStorage>(m_root->toStoragePath("player"));
|
m_playerStorage = make_shared<PlayerStorage>(m_root->toStoragePath("player"));
|
||||||
m_statistics = make_shared<Statistics>(m_root->toStoragePath("player"), appController()->statisticsService());
|
m_statistics = make_shared<Statistics>(m_root->toStoragePath("player"), appController()->statisticsService());
|
||||||
m_universeClient = make_shared<UniverseClient>(m_playerStorage, m_statistics);
|
m_universeClient = make_shared<UniverseClient>(m_playerStorage, m_statistics);
|
||||||
|
|
||||||
m_universeClient->setLuaCallbacks("input", LuaBindings::makeInputCallbacks());
|
m_universeClient->setLuaCallbacks("input", LuaBindings::makeInputCallbacks());
|
||||||
m_universeClient->setLuaCallbacks("voice", LuaBindings::makeVoiceCallbacks());
|
m_universeClient->setLuaCallbacks("voice", LuaBindings::makeVoiceCallbacks());
|
||||||
|
|
||||||
|
m_universeClient->playerReloadCallback() = [&]() {
|
||||||
|
if (auto paneManager = m_mainInterface->paneManager()) {
|
||||||
|
if (auto inventory = paneManager->registeredPane<InventoryPane>(MainInterfacePanes::Inventory))
|
||||||
|
inventory->clearChangedSlots();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
m_mainMixer->setUniverseClient(m_universeClient);
|
m_mainMixer->setUniverseClient(m_universeClient);
|
||||||
m_titleScreen = make_shared<TitleScreen>(m_playerStorage, m_mainMixer->mixer());
|
m_titleScreen = make_shared<TitleScreen>(m_playerStorage, m_mainMixer->mixer());
|
||||||
if (auto renderer = Application::renderer())
|
if (auto renderer = Application::renderer())
|
||||||
|
@ -112,6 +112,7 @@ SET (star_core_HEADERS
|
|||||||
StarStringView.hpp
|
StarStringView.hpp
|
||||||
StarStrongTypedef.hpp
|
StarStrongTypedef.hpp
|
||||||
StarTcp.hpp
|
StarTcp.hpp
|
||||||
|
StarText.hpp
|
||||||
StarThread.hpp
|
StarThread.hpp
|
||||||
StarTickRateMonitor.hpp
|
StarTickRateMonitor.hpp
|
||||||
StarTime.hpp
|
StarTime.hpp
|
||||||
@ -171,6 +172,7 @@ SET (star_core_SOURCES
|
|||||||
StarString.cpp
|
StarString.cpp
|
||||||
StarStringView.cpp
|
StarStringView.cpp
|
||||||
StarTcp.cpp
|
StarTcp.cpp
|
||||||
|
StarText.cpp
|
||||||
StarThread.cpp
|
StarThread.cpp
|
||||||
StarTime.cpp
|
StarTime.cpp
|
||||||
StarTickRateMonitor.cpp
|
StarTickRateMonitor.cpp
|
||||||
|
89
source/core/StarText.cpp
Normal file
89
source/core/StarText.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "StarText.hpp"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
namespace Star {
|
||||||
|
|
||||||
|
namespace Text {
|
||||||
|
static auto stripEscapeRegex = std::regex(strf("\\{:c}[^;]*{:c}", CmdEsc, EndEsc));
|
||||||
|
String stripEscapeCodes(String const& s) {
|
||||||
|
return std::regex_replace(s.utf8(), stripEscapeRegex, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string escapeChars = strf("{:c}{:c}", CmdEsc, StartEsc);
|
||||||
|
|
||||||
|
bool processText(StringView text, TextCallback textFunc, CommandsCallback commandsFunc, bool includeCommandSides) {
|
||||||
|
std::string_view escChars(escapeChars);
|
||||||
|
|
||||||
|
std::string_view str = text.utf8();
|
||||||
|
while (true) {
|
||||||
|
size_t escape = str.find_first_of(escChars);
|
||||||
|
if (escape != NPos) {
|
||||||
|
escape = str.find_first_not_of(escChars, escape) - 1; // jump to the last ^
|
||||||
|
|
||||||
|
size_t end = str.find_first_of(EndEsc, escape);
|
||||||
|
if (end != NPos) {
|
||||||
|
if (escape && !textFunc(str.substr(0, escape)))
|
||||||
|
return false;
|
||||||
|
if (commandsFunc) {
|
||||||
|
StringView commands = includeCommandSides
|
||||||
|
? str.substr(escape, end - escape + 1)
|
||||||
|
: str.substr(escape + 1, end - escape - 1);
|
||||||
|
if (!commands.empty() && !commandsFunc(commands))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
str = str.substr(end + 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!str.empty())
|
||||||
|
return textFunc(str);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The below two functions aren't used anymore, not bothering with StringView for them
|
||||||
|
String preprocessEscapeCodes(String const& s) {
|
||||||
|
bool escape = false;
|
||||||
|
std::string result = s.utf8();
|
||||||
|
|
||||||
|
size_t escapeStartIdx = 0;
|
||||||
|
for (size_t i = 0; i < result.size(); i++) {
|
||||||
|
auto& c = result[i];
|
||||||
|
if (isEscapeCode(c)) {
|
||||||
|
escape = true;
|
||||||
|
escapeStartIdx = i;
|
||||||
|
}
|
||||||
|
if ((c <= SpecialCharLimit) && !(c == StartEsc))
|
||||||
|
escape = false;
|
||||||
|
if ((c == EndEsc) && escape)
|
||||||
|
result[escapeStartIdx] = StartEsc;
|
||||||
|
}
|
||||||
|
return {result};
|
||||||
|
}
|
||||||
|
|
||||||
|
String extractCodes(String const& s) {
|
||||||
|
bool escape = false;
|
||||||
|
StringList result;
|
||||||
|
String escapeCode;
|
||||||
|
for (auto c : preprocessEscapeCodes(s)) {
|
||||||
|
if (c == StartEsc)
|
||||||
|
escape = true;
|
||||||
|
if (c == EndEsc) {
|
||||||
|
escape = false;
|
||||||
|
for (auto command : escapeCode.split(','))
|
||||||
|
result.append(command);
|
||||||
|
escapeCode = "";
|
||||||
|
}
|
||||||
|
if (escape && (c != StartEsc))
|
||||||
|
escapeCode.append(c);
|
||||||
|
}
|
||||||
|
if (!result.size())
|
||||||
|
return "";
|
||||||
|
return "^" + result.join(",") + ";";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
source/core/StarText.hpp
Normal file
26
source/core/StarText.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef STAR_TEXT_HPP
|
||||||
|
#define STAR_TEXT_HPP
|
||||||
|
#include "StarString.hpp"
|
||||||
|
#include "StarStringView.hpp"
|
||||||
|
|
||||||
|
namespace Star {
|
||||||
|
|
||||||
|
namespace Text {
|
||||||
|
unsigned char const StartEsc = '\x1b';
|
||||||
|
unsigned char const EndEsc = ';';
|
||||||
|
unsigned char const CmdEsc = '^';
|
||||||
|
unsigned char const SpecialCharLimit = ' ';
|
||||||
|
|
||||||
|
String stripEscapeCodes(String const& s);
|
||||||
|
inline bool isEscapeCode(char c) { return c == CmdEsc || c == StartEsc; }
|
||||||
|
|
||||||
|
typedef function<bool(StringView text)> TextCallback;
|
||||||
|
typedef function<bool(StringView commands)> CommandsCallback;
|
||||||
|
bool processText(StringView text, TextCallback textFunc, CommandsCallback commandsFunc = CommandsCallback(), bool includeCommandSides = false);
|
||||||
|
String preprocessEscapeCodes(String const& s);
|
||||||
|
String extractCodes(String const& s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -43,7 +43,7 @@ String Time::printDuration(double time) {
|
|||||||
seconds = strf("{} second{}", numSeconds, numSeconds == 1 ? "" : "s");
|
seconds = strf("{} second{}", numSeconds, numSeconds == 1 ? "" : "s");
|
||||||
}
|
}
|
||||||
|
|
||||||
int numMilliseconds = round(time * 1000);
|
int numMilliseconds = round(fmod(time, 1.0) * 1000);
|
||||||
milliseconds = strf("{} millisecond{}", numMilliseconds, numMilliseconds == 1 ? "" : "s");
|
milliseconds = strf("{} millisecond{}", numMilliseconds, numMilliseconds == 1 ? "" : "s");
|
||||||
|
|
||||||
return String::joinWith(", ", hours, minutes, seconds, milliseconds);
|
return String::joinWith(", ", hours, minutes, seconds, milliseconds);
|
||||||
|
@ -50,7 +50,8 @@ ClientCommandProcessor::ClientCommandProcessor(UniverseClientPtr universeClient,
|
|||||||
{"giveessentialitem", bind(&ClientCommandProcessor::giveEssentialItem, this, _1)},
|
{"giveessentialitem", bind(&ClientCommandProcessor::giveEssentialItem, this, _1)},
|
||||||
{"maketechavailable", bind(&ClientCommandProcessor::makeTechAvailable, this, _1)},
|
{"maketechavailable", bind(&ClientCommandProcessor::makeTechAvailable, this, _1)},
|
||||||
{"enabletech", bind(&ClientCommandProcessor::enableTech, this, _1)},
|
{"enabletech", bind(&ClientCommandProcessor::enableTech, this, _1)},
|
||||||
{"upgradeship", bind(&ClientCommandProcessor::upgradeShip, this, _1)}
|
{"upgradeship", bind(&ClientCommandProcessor::upgradeShip, this, _1)},
|
||||||
|
{"swap", bind(&ClientCommandProcessor::swap, this, _1)}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +305,7 @@ String ClientCommandProcessor::playTime() {
|
|||||||
|
|
||||||
String ClientCommandProcessor::deathCount() {
|
String ClientCommandProcessor::deathCount() {
|
||||||
auto deaths = m_universeClient->mainPlayer()->log()->deathCount();
|
auto deaths = m_universeClient->mainPlayer()->log()->deathCount();
|
||||||
return strf("Total deaths: {}{}", deaths, deaths == 0 ? ". Well done!" : "");
|
return deaths ? strf("Total deaths: {}", deaths) : "Total deaths: 0. Well done!";
|
||||||
}
|
}
|
||||||
|
|
||||||
String ClientCommandProcessor::cinema(String const& argumentsString) {
|
String ClientCommandProcessor::cinema(String const& argumentsString) {
|
||||||
@ -408,4 +409,16 @@ String ClientCommandProcessor::upgradeShip(String const& argumentsString) {
|
|||||||
return strf("Upgraded ship");
|
return strf("Upgraded ship");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ClientCommandProcessor::swap(String const& argumentsString) {
|
||||||
|
auto arguments = m_parser.tokenizeToStringList(argumentsString);
|
||||||
|
|
||||||
|
if (arguments.size() == 0)
|
||||||
|
return "Not enouch arguments to /swap";
|
||||||
|
|
||||||
|
if (m_universeClient->switchPlayer(arguments[0]))
|
||||||
|
return "Successfully swapped player";
|
||||||
|
else
|
||||||
|
return "Failed to swap player";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ private:
|
|||||||
String makeTechAvailable(String const& argumentsString);
|
String makeTechAvailable(String const& argumentsString);
|
||||||
String enableTech(String const& argumentsString);
|
String enableTech(String const& argumentsString);
|
||||||
String upgradeShip(String const& argumentsString);
|
String upgradeShip(String const& argumentsString);
|
||||||
|
String swap(String const& argumentsString);
|
||||||
|
|
||||||
UniverseClientPtr m_universeClient;
|
UniverseClientPtr m_universeClient;
|
||||||
CinematicPtr m_cinematicOverlay;
|
CinematicPtr m_cinematicOverlay;
|
||||||
|
@ -210,7 +210,7 @@ bool InventoryPane::giveContainerResult(ContainerResult result) {
|
|||||||
if (!m_expectingSwap)
|
if (!m_expectingSwap)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (auto item : result) {
|
for (auto& item : result) {
|
||||||
auto inv = m_player->inventory();
|
auto inv = m_player->inventory();
|
||||||
m_player->triggerPickupEvents(item);
|
m_player->triggerPickupEvents(item);
|
||||||
|
|
||||||
@ -224,18 +224,25 @@ bool InventoryPane::giveContainerResult(ContainerResult result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InventoryPane::updateItems() {
|
void InventoryPane::updateItems() {
|
||||||
for (auto p : m_itemGrids)
|
for (auto& p : m_itemGrids)
|
||||||
p.second->updateItemState();
|
p.second->updateItemState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InventoryPane::containsNewItems() const {
|
bool InventoryPane::containsNewItems() const {
|
||||||
for (auto p : m_itemGrids) {
|
for (auto& p : m_itemGrids) {
|
||||||
if (p.second->slotsChanged())
|
if (p.second->slotsChanged())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InventoryPane::clearChangedSlots() {
|
||||||
|
for (auto& p : m_itemGrids) {
|
||||||
|
p.second->updateItemState();
|
||||||
|
p.second->clearChangedSlots();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InventoryPane::update(float dt) {
|
void InventoryPane::update(float dt) {
|
||||||
auto inventory = m_player->inventory();
|
auto inventory = m_player->inventory();
|
||||||
auto context = Widget::context();
|
auto context = Widget::context();
|
||||||
|
@ -33,6 +33,7 @@ public:
|
|||||||
// this is a little hacky and should probably be checked in the player inventory instead
|
// this is a little hacky and should probably be checked in the player inventory instead
|
||||||
void updateItems();
|
void updateItems();
|
||||||
bool containsNewItems() const;
|
bool containsNewItems() const;
|
||||||
|
void clearChangedSlots();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void update(float dt) override;
|
virtual void update(float dt) override;
|
||||||
|
@ -40,7 +40,7 @@ TeamBar::TeamBar(MainInterface* mainInterface, UniverseClientPtr client) {
|
|||||||
return;
|
return;
|
||||||
auto position = jsonToVec2I(Root::singleton().assets()->json("/interface/windowconfig/teambar.config:selfMenuOffset"));
|
auto position = jsonToVec2I(Root::singleton().assets()->json("/interface/windowconfig/teambar.config:selfMenuOffset"));
|
||||||
position[1] += windowHeight() / m_guiContext->interfaceScale();
|
position[1] += windowHeight() / m_guiContext->interfaceScale();
|
||||||
showMemberMenu(m_client->mainPlayer()->clientContext()->serverUuid(), position);
|
showMemberMenu(m_client->mainPlayer()->clientContext()->playerUuid(), position);
|
||||||
});
|
});
|
||||||
|
|
||||||
reader.construct(assets->json("/interface/windowconfig/teambar.config:paneLayout"), this);
|
reader.construct(assets->json("/interface/windowconfig/teambar.config:paneLayout"), this);
|
||||||
@ -155,7 +155,7 @@ void TeamBar::buildTeamBar() {
|
|||||||
int memberSize = assets->json("/interface/windowconfig/teambar.config:memberSize").toInt();
|
int memberSize = assets->json("/interface/windowconfig/teambar.config:memberSize").toInt();
|
||||||
int memberSpacing = assets->json("/interface/windowconfig/teambar.config:memberSpacing").toInt();
|
int memberSpacing = assets->json("/interface/windowconfig/teambar.config:memberSpacing").toInt();
|
||||||
|
|
||||||
Uuid myUuid = player->clientContext()->serverUuid();
|
Uuid myUuid = player->clientContext()->playerUuid();
|
||||||
for (auto member : teamClient->members()) {
|
for (auto member : teamClient->members()) {
|
||||||
if (member.uuid == myUuid) {
|
if (member.uuid == myUuid) {
|
||||||
memberIndex++;
|
memberIndex++;
|
||||||
@ -360,7 +360,7 @@ void TeamMemberMenu::update(float dt) {
|
|||||||
|
|
||||||
void TeamMemberMenu::updateWidgets() {
|
void TeamMemberMenu::updateWidgets() {
|
||||||
bool isLeader = m_owner->m_client->teamClient()->isTeamLeader();
|
bool isLeader = m_owner->m_client->teamClient()->isTeamLeader();
|
||||||
bool isSelf = m_owner->m_client->mainPlayer()->clientContext()->serverUuid() == m_memberUuid;
|
bool isSelf = m_owner->m_client->mainPlayer()->clientContext()->playerUuid() == m_memberUuid;
|
||||||
|
|
||||||
fetchChild<ButtonWidget>("beamToShip")->setEnabled(m_canBeam);
|
fetchChild<ButtonWidget>("beamToShip")->setEnabled(m_canBeam);
|
||||||
fetchChild<ButtonWidget>("makeLeader")->setEnabled(isLeader && !isSelf);
|
fetchChild<ButtonWidget>("makeLeader")->setEnabled(isLeader && !isSelf);
|
||||||
|
@ -24,8 +24,9 @@ DataStream& operator<<(DataStream& ds, ShipUpgrades const& upgrades) {
|
|||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientContext::ClientContext(Uuid serverUuid) {
|
ClientContext::ClientContext(Uuid serverUuid, Uuid playerUuid) {
|
||||||
m_serverUuid = move(serverUuid);
|
m_serverUuid = move(serverUuid);
|
||||||
|
m_playerUuid = move(playerUuid);
|
||||||
m_rpc = make_shared<JsonRpc>();
|
m_rpc = make_shared<JsonRpc>();
|
||||||
|
|
||||||
m_netGroup.addNetElement(&m_orbitWarpActionNetState);
|
m_netGroup.addNetElement(&m_orbitWarpActionNetState);
|
||||||
@ -40,6 +41,10 @@ Uuid ClientContext::serverUuid() const {
|
|||||||
return m_serverUuid;
|
return m_serverUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Uuid ClientContext::playerUuid() const {
|
||||||
|
return m_playerUuid;
|
||||||
|
}
|
||||||
|
|
||||||
CelestialCoordinate ClientContext::shipCoordinate() const {
|
CelestialCoordinate ClientContext::shipCoordinate() const {
|
||||||
return m_shipCoordinate.get();
|
return m_shipCoordinate.get();
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,12 @@ STAR_CLASS(ClientContext);
|
|||||||
|
|
||||||
class ClientContext {
|
class ClientContext {
|
||||||
public:
|
public:
|
||||||
ClientContext(Uuid serverUuid);
|
ClientContext(Uuid serverUuid, Uuid playerUuid);
|
||||||
|
|
||||||
Uuid serverUuid() const;
|
Uuid serverUuid() const;
|
||||||
|
// The player Uuid can differ from the mainPlayer's Uuid
|
||||||
|
// if the player has swapped character - use this for ship saving.
|
||||||
|
Uuid playerUuid() const;
|
||||||
|
|
||||||
// The coordinate for the world which the player's ship is currently
|
// The coordinate for the world which the player's ship is currently
|
||||||
// orbiting.
|
// orbiting.
|
||||||
@ -43,6 +46,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Uuid m_serverUuid;
|
Uuid m_serverUuid;
|
||||||
|
Uuid m_playerUuid;
|
||||||
|
|
||||||
JsonRpcPtr m_rpc;
|
JsonRpcPtr m_rpc;
|
||||||
|
|
||||||
NetElementTopGroup m_netGroup;
|
NetElementTopGroup m_netGroup;
|
||||||
|
@ -27,6 +27,25 @@ EntityId EntityMap::reserveEntityId() {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Maybe<EntityId> EntityMap::maybeReserveEntityId(EntityId entityId) {
|
||||||
|
if (m_spatialMap.size() >= (size_t)(m_endIdSpace - m_beginIdSpace))
|
||||||
|
throw EntityMapException("No more entity id space in EntityMap::reserveEntityId");
|
||||||
|
|
||||||
|
if (m_spatialMap.contains(entityId))
|
||||||
|
return {};
|
||||||
|
else
|
||||||
|
return entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityId EntityMap::reserveEntityId(EntityId entityId) {
|
||||||
|
if (auto reserved = maybeReserveEntityId(entityId))
|
||||||
|
return *reserved;
|
||||||
|
|
||||||
|
m_nextId = entityId;
|
||||||
|
return reserveEntityId();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void EntityMap::addEntity(EntityPtr entity) {
|
void EntityMap::addEntity(EntityPtr entity) {
|
||||||
auto position = entity->position();
|
auto position = entity->position();
|
||||||
auto boundBox = entity->metaBoundBox();
|
auto boundBox = entity->metaBoundBox();
|
||||||
|
@ -30,6 +30,10 @@ public:
|
|||||||
|
|
||||||
// Get the next free id in the entity id space.
|
// Get the next free id in the entity id space.
|
||||||
EntityId reserveEntityId();
|
EntityId reserveEntityId();
|
||||||
|
// Or a specific one, can fail.
|
||||||
|
Maybe<EntityId> maybeReserveEntityId(EntityId entityId);
|
||||||
|
// If it doesn't matter that we don't get the one want
|
||||||
|
EntityId reserveEntityId(EntityId entityId);
|
||||||
|
|
||||||
// Add an entity to this EntityMap. The entity must already be initialized
|
// Add an entity to this EntityMap. The entity must already be initialized
|
||||||
// and have a unique EntityId returned by reserveEntityId.
|
// and have a unique EntityId returned by reserveEntityId.
|
||||||
|
@ -56,6 +56,7 @@ Player::Player(PlayerConfigPtr config, Uuid uuid) {
|
|||||||
auto assets = Root::singleton().assets();
|
auto assets = Root::singleton().assets();
|
||||||
|
|
||||||
m_config = config;
|
m_config = config;
|
||||||
|
m_client = nullptr;
|
||||||
|
|
||||||
m_state = State::Idle;
|
m_state = State::Idle;
|
||||||
m_emoteState = HumanoidEmote::Idle;
|
m_emoteState = HumanoidEmote::Idle;
|
||||||
@ -186,13 +187,35 @@ Player::Player(PlayerConfigPtr config, Uuid uuid) {
|
|||||||
m_netGroup.setNeedsStoreCallback(bind(&Player::setNetStates, this));
|
m_netGroup.setNeedsStoreCallback(bind(&Player::setNetStates, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Player::Player(PlayerConfigPtr config, ByteArray const& netStore) : Player(config) {
|
||||||
|
DataStreamBuffer ds(netStore);
|
||||||
|
|
||||||
|
setUniqueId(ds.read<String>());
|
||||||
|
|
||||||
|
ds.read(m_description);
|
||||||
|
ds.read(m_modeType);
|
||||||
|
ds.read(m_identity);
|
||||||
|
|
||||||
|
m_humanoid = make_shared<Humanoid>(Root::singleton().speciesDatabase()->species(m_identity.species)->humanoidConfig());
|
||||||
|
m_humanoid->setIdentity(m_identity);
|
||||||
|
m_movementController->resetBaseParameters(ActorMovementParameters(jsonMerge(m_humanoid->defaultMovementParameters(), m_config->movementParameters)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Player::Player(PlayerConfigPtr config, Json const& diskStore) : Player(config) {
|
Player::Player(PlayerConfigPtr config, Json const& diskStore) : Player(config) {
|
||||||
|
diskLoad(diskStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::diskLoad(Json const& diskStore) {
|
||||||
setUniqueId(diskStore.getString("uuid"));
|
setUniqueId(diskStore.getString("uuid"));
|
||||||
m_description = diskStore.getString("description");
|
m_description = diskStore.getString("description");
|
||||||
setModeType(PlayerModeNames.getLeft(diskStore.getString("modeType")));
|
setModeType(PlayerModeNames.getLeft(diskStore.getString("modeType")));
|
||||||
m_shipUpgrades = ShipUpgrades(diskStore.get("shipUpgrades"));
|
m_shipUpgrades = ShipUpgrades(diskStore.get("shipUpgrades"));
|
||||||
m_blueprints = make_shared<PlayerBlueprints>(diskStore.get("blueprints"));
|
m_blueprints = make_shared<PlayerBlueprints>(diskStore.get("blueprints"));
|
||||||
m_universeMap = make_shared<PlayerUniverseMap>(diskStore.get("universeMap"));
|
m_universeMap = make_shared<PlayerUniverseMap>(diskStore.get("universeMap"));
|
||||||
|
if (m_clientContext)
|
||||||
|
m_universeMap->setServerUuid(m_clientContext->serverUuid());
|
||||||
|
|
||||||
m_codexes = make_shared<PlayerCodexes>(diskStore.get("codexes"));
|
m_codexes = make_shared<PlayerCodexes>(diskStore.get("codexes"));
|
||||||
m_techs = make_shared<PlayerTech>(diskStore.get("techs"));
|
m_techs = make_shared<PlayerTech>(diskStore.get("techs"));
|
||||||
m_identity = HumanoidIdentity(diskStore.get("identity"));
|
m_identity = HumanoidIdentity(diskStore.get("identity"));
|
||||||
@ -208,48 +231,39 @@ Player::Player(PlayerConfigPtr config, Json const& diskStore) : Player(config) {
|
|||||||
|
|
||||||
m_log = make_shared<PlayerLog>(diskStore.get("log"));
|
m_log = make_shared<PlayerLog>(diskStore.get("log"));
|
||||||
|
|
||||||
m_codexes->learnInitialCodexes(species());
|
auto speciesDef = Root::singleton().speciesDatabase()->species(m_identity.species);
|
||||||
|
|
||||||
// Make sure to merge the stored player blueprints with what a new player
|
|
||||||
// would get as default.
|
|
||||||
for (auto const& descriptor : m_config->defaultBlueprints)
|
|
||||||
m_blueprints->add(descriptor);
|
|
||||||
for (auto const& descriptor : Root::singleton().speciesDatabase()->species(m_identity.species)->defaultBlueprints())
|
|
||||||
m_blueprints->add(descriptor);
|
|
||||||
|
|
||||||
m_questManager->diskLoad(diskStore.get("quests", JsonObject{}));
|
m_questManager->diskLoad(diskStore.get("quests", JsonObject{}));
|
||||||
m_companions->diskLoad(diskStore.get("companions", JsonObject{}));
|
m_companions->diskLoad(diskStore.get("companions", JsonObject{}));
|
||||||
m_deployment->diskLoad(diskStore.get("deployment", JsonObject{}));
|
m_deployment->diskLoad(diskStore.get("deployment", JsonObject{}));
|
||||||
m_humanoid = make_shared<Humanoid>(Root::singleton().speciesDatabase()->species(m_identity.species)->humanoidConfig());
|
m_humanoid = make_shared<Humanoid>(speciesDef->humanoidConfig());
|
||||||
m_humanoid->setIdentity(m_identity);
|
m_humanoid->setIdentity(m_identity);
|
||||||
m_movementController->resetBaseParameters(ActorMovementParameters(jsonMerge(m_humanoid->defaultMovementParameters(), m_config->movementParameters)));
|
m_movementController->resetBaseParameters(ActorMovementParameters(jsonMerge(m_humanoid->defaultMovementParameters(), m_config->movementParameters)));
|
||||||
m_effectsAnimator->setGlobalTag("effectDirectives", Root::singleton().speciesDatabase()->species(m_identity.species)->effectDirectives());
|
m_effectsAnimator->setGlobalTag("effectDirectives", speciesDef->effectDirectives());
|
||||||
|
|
||||||
m_genericProperties = diskStore.getObject("genericProperties");
|
m_genericProperties = diskStore.getObject("genericProperties");
|
||||||
|
|
||||||
refreshEquipment();
|
refreshEquipment();
|
||||||
|
|
||||||
|
m_codexes->learnInitialCodexes(species());
|
||||||
|
|
||||||
m_aiState = AiState(diskStore.get("aiState", JsonObject{}));
|
m_aiState = AiState(diskStore.get("aiState", JsonObject{}));
|
||||||
|
|
||||||
|
for (auto& script : m_genericScriptContexts)
|
||||||
|
script.second->setScriptStorage({});
|
||||||
|
|
||||||
for (auto& p : diskStore.get("genericScriptStorage", JsonObject{}).toObject()) {
|
for (auto& p : diskStore.get("genericScriptStorage", JsonObject{}).toObject()) {
|
||||||
if (auto script = m_genericScriptContexts.maybe(p.first).value({})) {
|
if (auto script = m_genericScriptContexts.maybe(p.first).value({})) {
|
||||||
script->setScriptStorage(p.second.toObject());
|
script->setScriptStorage(p.second.toObject());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Player::Player(PlayerConfigPtr config, ByteArray const& netStore) : Player(config) {
|
// Make sure to merge the stored player blueprints with what a new player
|
||||||
DataStreamBuffer ds(netStore);
|
// would get as default.
|
||||||
|
for (auto const& descriptor : m_config->defaultBlueprints)
|
||||||
setUniqueId(ds.read<String>());
|
m_blueprints->add(descriptor);
|
||||||
|
for (auto const& descriptor : speciesDef->defaultBlueprints())
|
||||||
ds.read(m_description);
|
m_blueprints->add(descriptor);
|
||||||
ds.read(m_modeType);
|
|
||||||
ds.read(m_identity);
|
|
||||||
|
|
||||||
m_humanoid = make_shared<Humanoid>(Root::singleton().speciesDatabase()->species(m_identity.species)->humanoidConfig());
|
|
||||||
m_humanoid->setIdentity(m_identity);
|
|
||||||
m_movementController->resetBaseParameters(ActorMovementParameters(jsonMerge(m_humanoid->defaultMovementParameters(), m_config->movementParameters)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientContextPtr Player::clientContext() const {
|
ClientContextPtr Player::clientContext() const {
|
||||||
@ -279,6 +293,10 @@ EntityType Player::entityType() const {
|
|||||||
return EntityType::Player;
|
return EntityType::Player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClientEntityMode Player::clientEntityMode() const {
|
||||||
|
return ClientEntityMode::ClientPresenceMaster;
|
||||||
|
}
|
||||||
|
|
||||||
void Player::init(World* world, EntityId entityId, EntityMode mode) {
|
void Player::init(World* world, EntityId entityId, EntityMode mode) {
|
||||||
Entity::init(world, entityId, mode);
|
Entity::init(world, entityId, mode);
|
||||||
|
|
||||||
@ -1961,6 +1979,13 @@ void Player::setShipUpgrades(ShipUpgrades shipUpgrades) {
|
|||||||
m_shipUpgrades = move(shipUpgrades);
|
m_shipUpgrades = move(shipUpgrades);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::applyShipUpgrades(Json const& upgrades) {
|
||||||
|
if (m_clientContext->playerUuid() == uuid())
|
||||||
|
m_clientContext->rpcInterface()->invokeRemote("ship.applyShipUpgrades", upgrades);
|
||||||
|
else
|
||||||
|
m_shipUpgrades.apply(upgrades);
|
||||||
|
}
|
||||||
|
|
||||||
String Player::name() const {
|
String Player::name() const {
|
||||||
return m_identity.name;
|
return m_identity.name;
|
||||||
}
|
}
|
||||||
@ -2176,6 +2201,19 @@ List<PhysicsForceRegion> Player::forceRegions() const {
|
|||||||
return m_tools->forceRegions();
|
return m_tools->forceRegions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StatusControllerPtr Player::statusControllerPtr() {
|
||||||
|
return m_statusController;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActorMovementControllerPtr Player::movementControllerPtr() {
|
||||||
|
return m_movementController;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerConfigPtr Player::config() {
|
||||||
|
return m_config;
|
||||||
|
}
|
||||||
|
|
||||||
SongbookPtr Player::songbook() const {
|
SongbookPtr Player::songbook() const {
|
||||||
return m_songbook;
|
return m_songbook;
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,10 @@ class Player :
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Player(PlayerConfigPtr config, Uuid uuid = Uuid());
|
Player(PlayerConfigPtr config, Uuid uuid = Uuid());
|
||||||
Player(PlayerConfigPtr config, Json const& diskStore);
|
|
||||||
Player(PlayerConfigPtr config, ByteArray const& netStore);
|
Player(PlayerConfigPtr config, ByteArray const& netStore);
|
||||||
|
Player(PlayerConfigPtr config, Json const& diskStore);
|
||||||
|
|
||||||
|
void diskLoad(Json const& diskStore);
|
||||||
|
|
||||||
ClientContextPtr clientContext() const;
|
ClientContextPtr clientContext() const;
|
||||||
void setClientContext(ClientContextPtr clientContext);
|
void setClientContext(ClientContextPtr clientContext);
|
||||||
@ -79,6 +81,7 @@ public:
|
|||||||
ByteArray netStore();
|
ByteArray netStore();
|
||||||
|
|
||||||
EntityType entityType() const override;
|
EntityType entityType() const override;
|
||||||
|
ClientEntityMode clientEntityMode() const override;
|
||||||
|
|
||||||
void init(World* world, EntityId entityId, EntityMode mode) override;
|
void init(World* world, EntityId entityId, EntityMode mode) override;
|
||||||
void uninit() override;
|
void uninit() override;
|
||||||
@ -283,6 +286,7 @@ public:
|
|||||||
|
|
||||||
ShipUpgrades shipUpgrades();
|
ShipUpgrades shipUpgrades();
|
||||||
void setShipUpgrades(ShipUpgrades shipUpgrades);
|
void setShipUpgrades(ShipUpgrades shipUpgrades);
|
||||||
|
void applyShipUpgrades(Json const& upgrades);
|
||||||
|
|
||||||
String name() const override;
|
String name() const override;
|
||||||
void setName(String const& name);
|
void setName(String const& name);
|
||||||
@ -395,6 +399,11 @@ public:
|
|||||||
|
|
||||||
List<PhysicsForceRegion> forceRegions() const override;
|
List<PhysicsForceRegion> forceRegions() const override;
|
||||||
|
|
||||||
|
StatusControllerPtr statusControllerPtr();
|
||||||
|
ActorMovementControllerPtr movementControllerPtr();
|
||||||
|
|
||||||
|
PlayerConfigPtr config();
|
||||||
|
|
||||||
SongbookPtr songbook() const;
|
SongbookPtr songbook() const;
|
||||||
|
|
||||||
void finalizeCreation();
|
void finalizeCreation();
|
||||||
|
@ -755,9 +755,18 @@ void PlayerInventory::load(Json const& store) {
|
|||||||
m_equipment[EquipmentSlot::LegsCosmetic] = itemDatabase->diskLoad(store.get("legsCosmeticSlot"));
|
m_equipment[EquipmentSlot::LegsCosmetic] = itemDatabase->diskLoad(store.get("legsCosmeticSlot"));
|
||||||
m_equipment[EquipmentSlot::BackCosmetic] = itemDatabase->diskLoad(store.get("backCosmeticSlot"));
|
m_equipment[EquipmentSlot::BackCosmetic] = itemDatabase->diskLoad(store.get("backCosmeticSlot"));
|
||||||
|
|
||||||
auto itemBags = store.get("itemBags");
|
//reuse ItemBags so the Inventory pane still works after load()'ing into the same PlayerInventory again (from swap)
|
||||||
for (String const& bagType : itemBags.toObject().keys())
|
auto itemBags = store.get("itemBags").toObject();
|
||||||
m_bags[bagType] = make_shared<ItemBag>(ItemBag::loadStore(itemBags.get(bagType)));
|
eraseWhere(m_bags, [&](auto const& p) { return !itemBags.contains(p.first); });
|
||||||
|
for (auto const& p : itemBags) {
|
||||||
|
auto& bagType = p.first;
|
||||||
|
auto newBag = ItemBag::loadStore(p.second);
|
||||||
|
auto& bagPtr = m_bags[bagType];
|
||||||
|
if (bagPtr)
|
||||||
|
*bagPtr = move(newBag);
|
||||||
|
else
|
||||||
|
bagPtr = make_shared<ItemBag>(move(newBag));
|
||||||
|
}
|
||||||
|
|
||||||
m_swapSlot = itemDatabase->diskLoad(store.get("swapSlot"));
|
m_swapSlot = itemDatabase->diskLoad(store.get("swapSlot"));
|
||||||
m_trashSlot = itemDatabase->diskLoad(store.get("trashSlot"));
|
m_trashSlot = itemDatabase->diskLoad(store.get("trashSlot"));
|
||||||
@ -778,6 +787,7 @@ void PlayerInventory::load(Json const& store) {
|
|||||||
|
|
||||||
m_selectedActionBar = jsonToSelectedActionBarLocation(store.get("selectedActionBar"));
|
m_selectedActionBar = jsonToSelectedActionBarLocation(store.get("selectedActionBar"));
|
||||||
|
|
||||||
|
m_essential.clear();
|
||||||
m_essential[EssentialItem::BeamAxe] = itemDatabase->diskLoad(store.get("beamAxe"));
|
m_essential[EssentialItem::BeamAxe] = itemDatabase->diskLoad(store.get("beamAxe"));
|
||||||
m_essential[EssentialItem::WireTool] = itemDatabase->diskLoad(store.get("wireTool"));
|
m_essential[EssentialItem::WireTool] = itemDatabase->diskLoad(store.get("wireTool"));
|
||||||
m_essential[EssentialItem::PaintTool] = itemDatabase->diskLoad(store.get("paintTool"));
|
m_essential[EssentialItem::PaintTool] = itemDatabase->diskLoad(store.get("paintTool"));
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "StarAssets.hpp"
|
#include "StarAssets.hpp"
|
||||||
#include "StarEntityFactory.hpp"
|
#include "StarEntityFactory.hpp"
|
||||||
#include "StarRoot.hpp"
|
#include "StarRoot.hpp"
|
||||||
|
#include "StarText.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
@ -98,7 +99,28 @@ Maybe<Uuid> PlayerStorage::playerUuidAt(size_t index) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerStorage::savePlayer(PlayerPtr const& player) {
|
Maybe<Uuid> PlayerStorage::playerUuidByName(String const& name) {
|
||||||
|
String cleanMatch = Text::stripEscapeCodes(name).toLower();
|
||||||
|
Maybe<Uuid> uuid;
|
||||||
|
|
||||||
|
RecursiveMutexLocker locker(m_mutex);
|
||||||
|
|
||||||
|
size_t longest = SIZE_MAX;
|
||||||
|
for (auto& cache : m_savedPlayersCache) {
|
||||||
|
if (auto name = cache.second.optQueryString("identity.name")) {
|
||||||
|
auto cleanName = Text::stripEscapeCodes(*name).toLower();
|
||||||
|
auto len = cleanName.size();
|
||||||
|
if (len < longest && cleanName.utf8().rfind(cleanMatch.utf8()) == 0) {
|
||||||
|
longest = len;
|
||||||
|
uuid = cache.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json PlayerStorage::savePlayer(PlayerPtr const& player) {
|
||||||
auto entityFactory = Root::singleton().entityFactory();
|
auto entityFactory = Root::singleton().entityFactory();
|
||||||
auto versioningDatabase = Root::singleton().versioningDatabase();
|
auto versioningDatabase = Root::singleton().versioningDatabase();
|
||||||
|
|
||||||
@ -113,15 +135,28 @@ void PlayerStorage::savePlayer(PlayerPtr const& player) {
|
|||||||
VersionedJson versionedJson = entityFactory->storeVersionedJson(EntityType::Player, playerCacheData);
|
VersionedJson versionedJson = entityFactory->storeVersionedJson(EntityType::Player, playerCacheData);
|
||||||
VersionedJson::writeFile(versionedJson, File::relativeTo(m_storageDirectory, strf("{}.player", uuid.hex())));
|
VersionedJson::writeFile(versionedJson, File::relativeTo(m_storageDirectory, strf("{}.player", uuid.hex())));
|
||||||
}
|
}
|
||||||
|
return newPlayerData;
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe<Json> PlayerStorage::maybeGetPlayerData(Uuid const& uuid) {
|
||||||
|
RecursiveMutexLocker locker(m_mutex);
|
||||||
|
if (auto cache = m_savedPlayersCache.ptr(uuid))
|
||||||
|
return *cache;
|
||||||
|
else
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Json PlayerStorage::getPlayerData(Uuid const& uuid) {
|
||||||
|
auto data = maybeGetPlayerData(uuid);
|
||||||
|
if (!data)
|
||||||
|
throw PlayerException(strf("No such stored player with uuid '{}'", uuid.hex()));
|
||||||
|
else
|
||||||
|
return *data;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerPtr PlayerStorage::loadPlayer(Uuid const& uuid) {
|
PlayerPtr PlayerStorage::loadPlayer(Uuid const& uuid) {
|
||||||
RecursiveMutexLocker locker(m_mutex);
|
auto playerCacheData = getPlayerData(uuid);
|
||||||
if (!m_savedPlayersCache.contains(uuid))
|
|
||||||
throw PlayerException(strf("No such stored player with uuid '{}'", uuid.hex()));
|
|
||||||
|
|
||||||
auto entityFactory = Root::singleton().entityFactory();
|
auto entityFactory = Root::singleton().entityFactory();
|
||||||
auto const& playerCacheData = m_savedPlayersCache.get(uuid);
|
|
||||||
try {
|
try {
|
||||||
auto player = convert<Player>(entityFactory->diskLoadEntity(EntityType::Player, playerCacheData));
|
auto player = convert<Player>(entityFactory->diskLoadEntity(EntityType::Player, playerCacheData));
|
||||||
if (player->uuid() != uuid)
|
if (player->uuid() != uuid)
|
||||||
@ -129,6 +164,7 @@ PlayerPtr PlayerStorage::loadPlayer(Uuid const& uuid) {
|
|||||||
return player;
|
return player;
|
||||||
} catch (std::exception const& e) {
|
} catch (std::exception const& e) {
|
||||||
Logger::error("Error loading player file, ignoring! {}", outputException(e, false));
|
Logger::error("Error loading player file, ignoring! {}", outputException(e, false));
|
||||||
|
RecursiveMutexLocker locker(m_mutex);
|
||||||
m_savedPlayersCache.remove(uuid);
|
m_savedPlayersCache.remove(uuid);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,14 @@ public:
|
|||||||
size_t playerCount() const;
|
size_t playerCount() const;
|
||||||
// Returns nothing if index is out of bounds.
|
// Returns nothing if index is out of bounds.
|
||||||
Maybe<Uuid> playerUuidAt(size_t index);
|
Maybe<Uuid> playerUuidAt(size_t index);
|
||||||
|
// Returns nothing if name doesn't match a player.
|
||||||
|
Maybe<Uuid> playerUuidByName(String const& name);
|
||||||
|
|
||||||
void savePlayer(PlayerPtr const& player);
|
// Also returns the diskStore Json if needed.
|
||||||
|
Json savePlayer(PlayerPtr const& player);
|
||||||
|
|
||||||
|
Maybe<Json> maybeGetPlayerData(Uuid const& uuid);
|
||||||
|
Json getPlayerData(Uuid const& uuid);
|
||||||
PlayerPtr loadPlayer(Uuid const& uuid);
|
PlayerPtr loadPlayer(Uuid const& uuid);
|
||||||
void deletePlayer(Uuid const& uuid);
|
void deletePlayer(Uuid const& uuid);
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ bool QuestManager::canStart(QuestArcDescriptor const& questArc) const {
|
|||||||
if (!m_player->inventory()->hasItem(item))
|
if (!m_player->inventory()->hasItem(item))
|
||||||
return false;
|
return false;
|
||||||
if (questTemplate->requiredShipLevel) {
|
if (questTemplate->requiredShipLevel) {
|
||||||
if (m_player->clientContext()->shipUpgrades().shipLevel < *questTemplate->requiredShipLevel)
|
if (m_player->shipUpgrades().shipLevel < *questTemplate->requiredShipLevel)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,7 @@ public:
|
|||||||
Maybe<WarpAction> objectWarpAction(Uuid const& uuid) const;
|
Maybe<WarpAction> objectWarpAction(Uuid const& uuid) const;
|
||||||
|
|
||||||
virtual List<SystemObjectPtr> objects() const = 0;
|
virtual List<SystemObjectPtr> objects() const = 0;
|
||||||
|
virtual List<Uuid> objectKeys() const = 0;
|
||||||
virtual SystemObjectPtr getObject(Uuid const& uuid) const = 0;
|
virtual SystemObjectPtr getObject(Uuid const& uuid) const = 0;
|
||||||
|
|
||||||
SystemObjectConfig systemObjectConfig(String const& name, Uuid const& uuid) const;
|
SystemObjectConfig systemObjectConfig(String const& name, Uuid const& uuid) const;
|
||||||
|
@ -82,6 +82,10 @@ List<SystemObjectPtr> SystemWorldClient::objects() const {
|
|||||||
return m_objects.values();
|
return m_objects.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Uuid> SystemWorldClient::objectKeys() const {
|
||||||
|
return m_objects.keys();
|
||||||
|
}
|
||||||
|
|
||||||
SystemObjectPtr SystemWorldClient::getObject(Uuid const& uuid) const {
|
SystemObjectPtr SystemWorldClient::getObject(Uuid const& uuid) const {
|
||||||
return m_objects.maybe(uuid).value({});
|
return m_objects.maybe(uuid).value({});
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ public:
|
|||||||
void update(float dt);
|
void update(float dt);
|
||||||
|
|
||||||
List<SystemObjectPtr> objects() const override;
|
List<SystemObjectPtr> objects() const override;
|
||||||
|
List<Uuid> objectKeys() const override;
|
||||||
SystemObjectPtr getObject(Uuid const& uuid) const override;
|
SystemObjectPtr getObject(Uuid const& uuid) const override;
|
||||||
|
|
||||||
List<SystemClientShipPtr> ships() const;
|
List<SystemClientShipPtr> ships() const;
|
||||||
|
@ -247,6 +247,10 @@ List<SystemObjectPtr> SystemWorldServer::objects() const {
|
|||||||
return m_objects.values();
|
return m_objects.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Uuid> SystemWorldServer::objectKeys() const {
|
||||||
|
return m_objects.keys();
|
||||||
|
}
|
||||||
|
|
||||||
SystemObjectPtr SystemWorldServer::getObject(Uuid const& uuid) const {
|
SystemObjectPtr SystemWorldServer::getObject(Uuid const& uuid) const {
|
||||||
return m_objects.maybe(uuid).value({});
|
return m_objects.maybe(uuid).value({});
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ public:
|
|||||||
void update(float dt);
|
void update(float dt);
|
||||||
|
|
||||||
List<SystemObjectPtr> objects() const override;
|
List<SystemObjectPtr> objects() const override;
|
||||||
|
List<Uuid> objectKeys() const override;
|
||||||
SystemObjectPtr getObject(Uuid const& uuid) const override;
|
SystemObjectPtr getObject(Uuid const& uuid) const override;
|
||||||
|
|
||||||
List<ConnectionId> pullShipFlights();
|
List<ConnectionId> pullShipFlights();
|
||||||
|
@ -109,7 +109,7 @@ Maybe<String> UniverseClient::connect(UniverseConnection connection, bool allowA
|
|||||||
|
|
||||||
if (auto success = as<ConnectSuccessPacket>(packet)) {
|
if (auto success = as<ConnectSuccessPacket>(packet)) {
|
||||||
m_universeClock = make_shared<Clock>();
|
m_universeClock = make_shared<Clock>();
|
||||||
m_clientContext = make_shared<ClientContext>(success->serverUuid);
|
m_clientContext = make_shared<ClientContext>(success->serverUuid, m_mainPlayer->uuid());
|
||||||
m_teamClient = make_shared<TeamClient>(m_mainPlayer, m_clientContext);
|
m_teamClient = make_shared<TeamClient>(m_mainPlayer, m_clientContext);
|
||||||
m_mainPlayer->setClientContext(m_clientContext);
|
m_mainPlayer->setClientContext(m_clientContext);
|
||||||
m_mainPlayer->setStatistics(m_statistics);
|
m_mainPlayer->setStatistics(m_statistics);
|
||||||
@ -397,6 +397,10 @@ bool UniverseClient::playerOnOwnShip() const {
|
|||||||
return playerWorld().is<ClientShipWorldId>() && playerWorld().get<ClientShipWorldId>() == mainPlayer()->uuid();
|
return playerWorld().is<ClientShipWorldId>() && playerWorld().get<ClientShipWorldId>() == mainPlayer()->uuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UniverseClient::playerIsOriginal() const {
|
||||||
|
return m_clientContext->playerUuid() == mainPlayer()->uuid();
|
||||||
|
}
|
||||||
|
|
||||||
WorldId UniverseClient::playerWorld() const {
|
WorldId UniverseClient::playerWorld() const {
|
||||||
return m_clientContext->playerWorldId();
|
return m_clientContext->playerWorldId();
|
||||||
}
|
}
|
||||||
@ -473,6 +477,80 @@ void UniverseClient::stopLua() {
|
|||||||
m_scriptContexts.clear();
|
m_scriptContexts.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UniverseClient::reloadPlayer(Json const& data, Uuid const& uuid) {
|
||||||
|
auto player = mainPlayer();
|
||||||
|
auto world = worldClient();
|
||||||
|
bool inWorld = player->inWorld();
|
||||||
|
EntityId entityId = player->entityId();
|
||||||
|
|
||||||
|
if (m_playerReloadPreCallback)
|
||||||
|
m_playerReloadPreCallback();
|
||||||
|
|
||||||
|
if (inWorld)
|
||||||
|
world->removeEntity(entityId, false);
|
||||||
|
else {
|
||||||
|
m_respawning = false;
|
||||||
|
m_respawnTimer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Json originalData = m_playerStorage->savePlayer(player);
|
||||||
|
std::exception_ptr exception;
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto newData = data.set("movementController", originalData.get("movementController"));
|
||||||
|
player->diskLoad(newData);
|
||||||
|
}
|
||||||
|
catch (std::exception const& e) {
|
||||||
|
player->diskLoad(originalData);
|
||||||
|
exception = std::current_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
world->addEntity(player);
|
||||||
|
|
||||||
|
CelestialCoordinate coordinate = m_systemWorldClient->location();
|
||||||
|
player->universeMap()->addMappedCoordinate(coordinate);
|
||||||
|
player->universeMap()->filterMappedObjects(coordinate, m_systemWorldClient->objectKeys());
|
||||||
|
|
||||||
|
if (m_playerReloadCallback)
|
||||||
|
m_playerReloadCallback();
|
||||||
|
|
||||||
|
if (exception)
|
||||||
|
std::rethrow_exception(exception);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UniverseClient::switchPlayer(Uuid const& uuid) {
|
||||||
|
if (uuid == mainPlayer()->uuid())
|
||||||
|
return false;
|
||||||
|
else if (auto data = m_playerStorage->maybeGetPlayerData(uuid))
|
||||||
|
return reloadPlayer(*data, uuid);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UniverseClient::switchPlayer(size_t index) {
|
||||||
|
if (auto uuid = m_playerStorage->playerUuidAt(index))
|
||||||
|
return switchPlayer(*uuid);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UniverseClient::switchPlayer(String const& name) {
|
||||||
|
if (auto uuid = m_playerStorage->playerUuidByName(name))
|
||||||
|
return switchPlayer(*uuid);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniverseClient::Callback& UniverseClient::playerReloadPreCallback() {
|
||||||
|
return m_playerReloadPreCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniverseClient::Callback& UniverseClient::playerReloadCallback() {
|
||||||
|
return m_playerReloadCallback;
|
||||||
|
}
|
||||||
|
|
||||||
ClockConstPtr UniverseClient::universeClock() const {
|
ClockConstPtr UniverseClient::universeClock() const {
|
||||||
return m_universeClock;
|
return m_universeClock;
|
||||||
}
|
}
|
||||||
@ -518,10 +596,14 @@ void UniverseClient::handlePackets(List<PacketPtr> const& packets) {
|
|||||||
for (auto const& packet : packets) {
|
for (auto const& packet : packets) {
|
||||||
if (auto clientContextUpdate = as<ClientContextUpdatePacket>(packet)) {
|
if (auto clientContextUpdate = as<ClientContextUpdatePacket>(packet)) {
|
||||||
m_clientContext->readUpdate(clientContextUpdate->updateData);
|
m_clientContext->readUpdate(clientContextUpdate->updateData);
|
||||||
m_playerStorage->applyShipUpdates(m_mainPlayer->uuid(), m_clientContext->newShipUpdates());
|
m_playerStorage->applyShipUpdates(m_clientContext->playerUuid(), m_clientContext->newShipUpdates());
|
||||||
m_mainPlayer->setShipUpgrades(m_clientContext->shipUpgrades());
|
|
||||||
|
if (playerIsOriginal())
|
||||||
|
m_mainPlayer->setShipUpgrades(m_clientContext->shipUpgrades());
|
||||||
|
|
||||||
m_mainPlayer->setAdmin(m_clientContext->isAdmin());
|
m_mainPlayer->setAdmin(m_clientContext->isAdmin());
|
||||||
m_mainPlayer->setTeam(m_clientContext->team());
|
m_mainPlayer->setTeam(m_clientContext->team());
|
||||||
|
|
||||||
} else if (auto chatReceivePacket = as<ChatReceivePacket>(packet)) {
|
} else if (auto chatReceivePacket = as<ChatReceivePacket>(packet)) {
|
||||||
m_pendingMessages.append(chatReceivePacket->receivedMessage);
|
m_pendingMessages.append(chatReceivePacket->receivedMessage);
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ public:
|
|||||||
CelestialCoordinate shipCoordinate() const;
|
CelestialCoordinate shipCoordinate() const;
|
||||||
|
|
||||||
bool playerOnOwnShip() const;
|
bool playerOnOwnShip() const;
|
||||||
|
bool playerIsOriginal() const;
|
||||||
|
|
||||||
WorldId playerWorld() const;
|
WorldId playerWorld() const;
|
||||||
bool isAdmin() const;
|
bool isAdmin() const;
|
||||||
@ -90,6 +91,15 @@ public:
|
|||||||
void startLua();
|
void startLua();
|
||||||
void stopLua();
|
void stopLua();
|
||||||
|
|
||||||
|
bool reloadPlayer(Json const& data, Uuid const& uuid);
|
||||||
|
bool switchPlayer(Uuid const& uuid);
|
||||||
|
bool switchPlayer(size_t index);
|
||||||
|
bool switchPlayer(String const& name);
|
||||||
|
|
||||||
|
typedef std::function<void()> Callback;
|
||||||
|
Callback& playerReloadPreCallback();
|
||||||
|
Callback& playerReloadCallback();
|
||||||
|
|
||||||
ClockConstPtr universeClock() const;
|
ClockConstPtr universeClock() const;
|
||||||
CelestialLogConstPtr celestialLog() const;
|
CelestialLogConstPtr celestialLog() const;
|
||||||
JsonRpcInterfacePtr rpcInterface() const;
|
JsonRpcInterfacePtr rpcInterface() const;
|
||||||
@ -150,6 +160,9 @@ private:
|
|||||||
typedef LuaUpdatableComponent<LuaBaseComponent> ScriptComponent;
|
typedef LuaUpdatableComponent<LuaBaseComponent> ScriptComponent;
|
||||||
typedef shared_ptr<ScriptComponent> ScriptComponentPtr;
|
typedef shared_ptr<ScriptComponent> ScriptComponentPtr;
|
||||||
StringMap<ScriptComponentPtr> m_scriptContexts;
|
StringMap<ScriptComponentPtr> m_scriptContexts;
|
||||||
|
|
||||||
|
Callback m_playerReloadPreCallback;
|
||||||
|
Callback m_playerReloadCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -136,6 +136,40 @@ bool WorldClient::respawnInWorld() const {
|
|||||||
return m_respawnInWorld;
|
return m_respawnInWorld;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldClient::removeEntity(EntityId entityId, bool andDie) {
|
||||||
|
auto entity = m_entityMap->entity(entityId);
|
||||||
|
if (!entity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (andDie) {
|
||||||
|
ClientRenderCallback renderCallback;
|
||||||
|
entity->destroy(&renderCallback);
|
||||||
|
|
||||||
|
const List<Directives>* directives = nullptr;
|
||||||
|
if (auto& worldTemplate = m_worldTemplate) {
|
||||||
|
if (const auto& parameters = worldTemplate->worldParameters())
|
||||||
|
if (auto& globalDirectives = m_worldTemplate->worldParameters()->globalDirectives)
|
||||||
|
directives = &globalDirectives.get();
|
||||||
|
}
|
||||||
|
if (directives) {
|
||||||
|
int directiveIndex = unsigned(entity->entityId()) % directives->size();
|
||||||
|
for (auto& p : renderCallback.particles)
|
||||||
|
p.directives.append(directives->get(directiveIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_particles->addParticles(move(renderCallback.particles));
|
||||||
|
m_samples.appendAll(move(renderCallback.audios));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto version = m_masterEntitiesNetVersion.maybeTake(entity->entityId())) {
|
||||||
|
ByteArray finalNetState = entity->writeNetState(*version).first;
|
||||||
|
m_outgoingPackets.append(make_shared<EntityDestroyPacket>(entity->entityId(), move(finalNetState), andDie));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_entityMap->removeEntity(entityId);
|
||||||
|
entity->uninit();
|
||||||
|
}
|
||||||
|
|
||||||
WorldTemplateConstPtr WorldClient::currentTemplate() const {
|
WorldTemplateConstPtr WorldClient::currentTemplate() const {
|
||||||
return m_worldTemplate;
|
return m_worldTemplate;
|
||||||
}
|
}
|
||||||
@ -989,7 +1023,7 @@ void WorldClient::update(float dt) {
|
|||||||
action(this);
|
action(this);
|
||||||
|
|
||||||
List<EntityId> toRemove;
|
List<EntityId> toRemove;
|
||||||
List<EntityId> clientPresenceEntities{m_mainPlayer->entityId()};
|
List<EntityId> clientPresenceEntities;
|
||||||
m_entityMap->updateAllEntities([&](EntityPtr const& entity) {
|
m_entityMap->updateAllEntities([&](EntityPtr const& entity) {
|
||||||
entity->update(dt, m_currentStep);
|
entity->update(dt, m_currentStep);
|
||||||
|
|
||||||
@ -1415,40 +1449,6 @@ void WorldClient::sparkDamagedBlocks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldClient::removeEntity(EntityId entityId, bool andDie) {
|
|
||||||
auto entity = m_entityMap->entity(entityId);
|
|
||||||
if (!entity)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (andDie) {
|
|
||||||
ClientRenderCallback renderCallback;
|
|
||||||
entity->destroy(&renderCallback);
|
|
||||||
|
|
||||||
const List<Directives>* directives = nullptr;
|
|
||||||
if (auto& worldTemplate = m_worldTemplate) {
|
|
||||||
if (const auto& parameters = worldTemplate->worldParameters())
|
|
||||||
if (auto& globalDirectives = m_worldTemplate->worldParameters()->globalDirectives)
|
|
||||||
directives = &globalDirectives.get();
|
|
||||||
}
|
|
||||||
if (directives) {
|
|
||||||
int directiveIndex = unsigned(entity->entityId()) % directives->size();
|
|
||||||
for (auto& p : renderCallback.particles)
|
|
||||||
p.directives.append(directives->get(directiveIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_particles->addParticles(move(renderCallback.particles));
|
|
||||||
m_samples.appendAll(move(renderCallback.audios));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto version = m_masterEntitiesNetVersion.maybeTake(entity->entityId())) {
|
|
||||||
ByteArray finalNetState = entity->writeNetState(*version).first;
|
|
||||||
m_outgoingPackets.append(make_shared<EntityDestroyPacket>(entity->entityId(), move(finalNetState), andDie));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_entityMap->removeEntity(entityId);
|
|
||||||
entity->uninit();
|
|
||||||
}
|
|
||||||
|
|
||||||
InteractiveEntityPtr WorldClient::getInteractiveInRange(Vec2F const& targetPosition, Vec2F const& sourcePosition, float maxRange) const {
|
InteractiveEntityPtr WorldClient::getInteractiveInRange(Vec2F const& targetPosition, Vec2F const& sourcePosition, float maxRange) const {
|
||||||
if (!inWorld())
|
if (!inWorld())
|
||||||
return {};
|
return {};
|
||||||
|
@ -108,6 +108,8 @@ public:
|
|||||||
void reviveMainPlayer();
|
void reviveMainPlayer();
|
||||||
bool respawnInWorld() const;
|
bool respawnInWorld() const;
|
||||||
|
|
||||||
|
void removeEntity(EntityId entityId, bool andDie);
|
||||||
|
|
||||||
WorldTemplateConstPtr currentTemplate() const;
|
WorldTemplateConstPtr currentTemplate() const;
|
||||||
SkyConstPtr currentSky() const;
|
SkyConstPtr currentSky() const;
|
||||||
|
|
||||||
@ -214,8 +216,6 @@ private:
|
|||||||
|
|
||||||
void sparkDamagedBlocks();
|
void sparkDamagedBlocks();
|
||||||
|
|
||||||
void removeEntity(EntityId entityId, bool andDie);
|
|
||||||
|
|
||||||
Vec2I environmentBiomeTrackPosition() const;
|
Vec2I environmentBiomeTrackPosition() const;
|
||||||
AmbientNoisesDescriptionPtr currentAmbientNoises() const;
|
AmbientNoisesDescriptionPtr currentAmbientNoises() const;
|
||||||
WeatherNoisesDescriptionPtr currentWeatherNoises() const;
|
WeatherNoisesDescriptionPtr currentWeatherNoises() const;
|
||||||
|
@ -40,7 +40,7 @@ void UnlockItem::fireTriggered() {
|
|||||||
|
|
||||||
if (auto clientContext = player->clientContext()) {
|
if (auto clientContext = player->clientContext()) {
|
||||||
if (m_shipUpgrade)
|
if (m_shipUpgrade)
|
||||||
clientContext->rpcInterface()->invokeRemote("ship.applyShipUpgrades", JsonObject{{"shipLevel", *m_shipUpgrade}});
|
player->applyShipUpgrades(JsonObject{ {"shipLevel", *m_shipUpgrade} });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_unlockMessage.empty()) {
|
if (!m_unlockMessage.empty()) {
|
||||||
|
@ -112,11 +112,8 @@ LuaCallbacks LuaBindings::makePlayerCallbacks(Player* player) {
|
|||||||
player->interact(InteractAction(type, sourceEntityId.value(NullEntityId), configData));
|
player->interact(InteractAction(type, sourceEntityId.value(NullEntityId), configData));
|
||||||
});
|
});
|
||||||
|
|
||||||
callbacks.registerCallback("shipUpgrades", [player]() { return player->clientContext()->shipUpgrades().toJson(); });
|
callbacks.registerCallback("shipUpgrades", [player]() { return player->shipUpgrades().toJson(); });
|
||||||
|
callbacks.registerCallback("upgradeShip", [player](Json const& upgrades) { player->applyShipUpgrades(upgrades); });
|
||||||
callbacks.registerCallback("upgradeShip", [player](Json const& upgrades) {
|
|
||||||
player->clientContext()->rpcInterface()->invokeRemote("ship.applyShipUpgrades", upgrades);
|
|
||||||
});
|
|
||||||
|
|
||||||
callbacks.registerCallback("setUniverseFlag", [player](String const& flagName) {
|
callbacks.registerCallback("setUniverseFlag", [player](String const& flagName) {
|
||||||
player->clientContext()->rpcInterface()->invokeRemote("universe.setFlag", flagName);
|
player->clientContext()->rpcInterface()->invokeRemote("universe.setFlag", flagName);
|
||||||
|
@ -1,98 +1,11 @@
|
|||||||
#include "StarTextPainter.hpp"
|
#include "StarTextPainter.hpp"
|
||||||
#include "StarJsonExtra.hpp"
|
#include "StarJsonExtra.hpp"
|
||||||
|
#include "StarText.hpp"
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
namespace Text {
|
|
||||||
static auto stripEscapeRegex = std::regex(strf("\\{:c}[^;]*{:c}", CmdEsc, EndEsc));
|
|
||||||
String stripEscapeCodes(String const& s) {
|
|
||||||
return std::regex_replace(s.utf8(), stripEscapeRegex, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool isEscapeCode(char c) {
|
|
||||||
return c == CmdEsc || c == StartEsc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string escapeChars = strf("{:c}{:c}", CmdEsc, StartEsc);
|
|
||||||
|
|
||||||
typedef function<bool(StringView text)> TextCallback;
|
|
||||||
typedef function<bool(StringView commands)> CommandsCallback;
|
|
||||||
bool processText(StringView text, TextCallback textFunc, CommandsCallback commandsFunc = CommandsCallback(), bool includeCommandSides = false) {
|
|
||||||
std::string_view escChars(escapeChars);
|
|
||||||
|
|
||||||
std::string_view str = text.utf8();
|
|
||||||
while (true) {
|
|
||||||
size_t escape = str.find_first_of(escChars);
|
|
||||||
if (escape != NPos) {
|
|
||||||
escape = str.find_first_not_of(escChars, escape) - 1; // jump to the last ^
|
|
||||||
|
|
||||||
size_t end = str.find_first_of(EndEsc, escape);
|
|
||||||
if (end != NPos) {
|
|
||||||
if (escape && !textFunc(str.substr(0, escape)))
|
|
||||||
return false;
|
|
||||||
if (commandsFunc) {
|
|
||||||
StringView commands = includeCommandSides
|
|
||||||
? str.substr(escape, end - escape + 1)
|
|
||||||
: str.substr(escape + 1, end - escape - 1);
|
|
||||||
if (!commands.empty() && !commandsFunc(commands))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
str = str.substr(end + 1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!str.empty())
|
|
||||||
return textFunc(str);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The below two functions aren't used anymore, not bothering with StringView for them
|
|
||||||
String preprocessEscapeCodes(String const& s) {
|
|
||||||
bool escape = false;
|
|
||||||
std::string result = s.utf8();
|
|
||||||
|
|
||||||
size_t escapeStartIdx = 0;
|
|
||||||
for (size_t i = 0; i < result.size(); i++) {
|
|
||||||
auto& c = result[i];
|
|
||||||
if (isEscapeCode(c)) {
|
|
||||||
escape = true;
|
|
||||||
escapeStartIdx = i;
|
|
||||||
}
|
|
||||||
if ((c <= SpecialCharLimit) && !(c == StartEsc))
|
|
||||||
escape = false;
|
|
||||||
if ((c == EndEsc) && escape)
|
|
||||||
result[escapeStartIdx] = StartEsc;
|
|
||||||
}
|
|
||||||
return {result};
|
|
||||||
}
|
|
||||||
|
|
||||||
String extractCodes(String const& s) {
|
|
||||||
bool escape = false;
|
|
||||||
StringList result;
|
|
||||||
String escapeCode;
|
|
||||||
for (auto c : preprocessEscapeCodes(s)) {
|
|
||||||
if (c == StartEsc)
|
|
||||||
escape = true;
|
|
||||||
if (c == EndEsc) {
|
|
||||||
escape = false;
|
|
||||||
for (auto command : escapeCode.split(','))
|
|
||||||
result.append(command);
|
|
||||||
escapeCode = "";
|
|
||||||
}
|
|
||||||
if (escape && (c != StartEsc))
|
|
||||||
escapeCode.append(c);
|
|
||||||
}
|
|
||||||
if (!result.size())
|
|
||||||
return "";
|
|
||||||
return "^" + result.join(",") + ";";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextPositioning::TextPositioning() {
|
TextPositioning::TextPositioning() {
|
||||||
pos = Vec2F();
|
pos = Vec2F();
|
||||||
hAnchor = HorizontalAnchor::LeftAnchor;
|
hAnchor = HorizontalAnchor::LeftAnchor;
|
||||||
|
@ -10,17 +10,6 @@ namespace Star {
|
|||||||
|
|
||||||
STAR_CLASS(TextPainter);
|
STAR_CLASS(TextPainter);
|
||||||
|
|
||||||
namespace Text {
|
|
||||||
unsigned char const StartEsc = '\x1b';
|
|
||||||
unsigned char const EndEsc = ';';
|
|
||||||
unsigned char const CmdEsc = '^';
|
|
||||||
unsigned char const SpecialCharLimit = ' ';
|
|
||||||
|
|
||||||
String stripEscapeCodes(String const& s);
|
|
||||||
String preprocessEscapeCodes(String const& s);
|
|
||||||
String extractCodes(String const& s);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class FontMode {
|
enum class FontMode {
|
||||||
Normal,
|
Normal,
|
||||||
Shadow
|
Shadow
|
||||||
|
@ -198,12 +198,9 @@ void ItemGridWidget::updateItemState() {
|
|||||||
updateAllItemSlots();
|
updateAllItemSlots();
|
||||||
auto newState = slotItemNames();
|
auto newState = slotItemNames();
|
||||||
for (size_t i = 0; i < newState.size(); ++i) {
|
for (size_t i = 0; i < newState.size(); ++i) {
|
||||||
if (newState[i].empty()) {
|
if (newState[i].empty())
|
||||||
m_changedSlots.remove(i);
|
m_changedSlots.remove(i);
|
||||||
continue;
|
else if (newState[i].compare(m_itemNames[i]) != 0)
|
||||||
}
|
|
||||||
|
|
||||||
if (newState[i].compare(m_itemNames[i]) != 0)
|
|
||||||
m_changedSlots.insert(i);
|
m_changedSlots.insert(i);
|
||||||
}
|
}
|
||||||
m_itemNames = newState;
|
m_itemNames = newState;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "StarCasting.hpp"
|
#include "StarCasting.hpp"
|
||||||
#include "StarInputEvent.hpp"
|
#include "StarInputEvent.hpp"
|
||||||
#include "StarGuiContext.hpp"
|
#include "StarGuiContext.hpp"
|
||||||
|
#include "StarText.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user