Add loading icon when swapping character
This commit is contained in:
parent
994c533a0f
commit
c80b2d2dbc
34
assets/opensb/projectiles/opensb/playerloading.projectile
Normal file
34
assets/opensb/projectiles/opensb/playerloading.projectile
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"projectileName" : "opensb:playerloading",
|
||||||
|
"image" : "/projectiles/invisibleprojectile/invisibleprojectile.png",
|
||||||
|
"processing" : "?crop=0;0;1;1?multiply=0000?replace;0000=fff?scalenearest=15?blendmult=/animations/chatting/menu.png:1;0;0?multiply=fffffffe",
|
||||||
|
"damageTeam" : { "type" : "ghostly" },
|
||||||
|
"damageKind" : "default",
|
||||||
|
"power" : 0,
|
||||||
|
"acceleration" : 0,
|
||||||
|
"speed" : 0,
|
||||||
|
"timeToLive" : 0,
|
||||||
|
|
||||||
|
"periodicActions" : [
|
||||||
|
{
|
||||||
|
"time" : 0.00,
|
||||||
|
"repeat" : false,
|
||||||
|
"action" : "sound",
|
||||||
|
"options" : [ "/sfx/objects/mannequin_open.ogg" ]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"actionOnReap" : [
|
||||||
|
{
|
||||||
|
"action" : "sound",
|
||||||
|
"options" : [ "/sfx/objects/mannequin_close.ogg" ]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"movementSettings" : {
|
||||||
|
"collisionEnabled" : true,
|
||||||
|
"gravityEnabled" : false,
|
||||||
|
"physicsEffectCategories" : [],
|
||||||
|
"collisionPoly" : []
|
||||||
|
}
|
||||||
|
}
|
@ -526,7 +526,7 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotation) {
|
|||||||
auto backArmDrawable = [&](String const& frameSet, Directives const& directives) -> Drawable {
|
auto backArmDrawable = [&](String const& frameSet, Directives const& directives) -> Drawable {
|
||||||
String image = strf("{}:{}", frameSet, backHand.backFrame);
|
String image = strf("{}:{}", frameSet, backHand.backFrame);
|
||||||
Drawable backArm = Drawable::makeImage(move(image), 1.0f / TilePixels, true, backArmFrameOffset);
|
Drawable backArm = Drawable::makeImage(move(image), 1.0f / TilePixels, true, backArmFrameOffset);
|
||||||
backArm.imagePart().addDirectives(directives);
|
backArm.imagePart().addDirectives(directives, true);
|
||||||
backArm.rotate(backHand.angle, backArmFrameOffset + m_backArmRotationCenter + m_backArmOffset);
|
backArm.rotate(backHand.angle, backArmFrameOffset + m_backArmRotationCenter + m_backArmOffset);
|
||||||
return backArm;
|
return backArm;
|
||||||
};
|
};
|
||||||
@ -710,7 +710,7 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotation) {
|
|||||||
auto frontArmDrawable = [&](String const& frameSet, Directives const& directives) -> Drawable {
|
auto frontArmDrawable = [&](String const& frameSet, Directives const& directives) -> Drawable {
|
||||||
String image = strf("{}:{}", frameSet, frontHand.frontFrame);
|
String image = strf("{}:{}", frameSet, frontHand.frontFrame);
|
||||||
Drawable frontArm = Drawable::makeImage(image, 1.0f / TilePixels, true, frontArmFrameOffset);
|
Drawable frontArm = Drawable::makeImage(image, 1.0f / TilePixels, true, frontArmFrameOffset);
|
||||||
frontArm.imagePart().addDirectives(directives);
|
frontArm.imagePart().addDirectives(directives, true);
|
||||||
frontArm.rotate(frontHand.angle, frontArmFrameOffset + m_frontArmRotationCenter);
|
frontArm.rotate(frontHand.angle, frontArmFrameOffset + m_frontArmRotationCenter);
|
||||||
return frontArm;
|
return frontArm;
|
||||||
};
|
};
|
||||||
|
@ -358,7 +358,9 @@ void Projectile::render(RenderCallback* renderCallback) {
|
|||||||
|
|
||||||
m_effectEmitter->render(renderCallback);
|
m_effectEmitter->render(renderCallback);
|
||||||
|
|
||||||
Drawable drawable = Drawable::makeImage(drawableFrame(), 1.0f / TilePixels, true, Vec2F());
|
String image = strf("{}:{}{}", m_config->image, m_frame, m_imageSuffix);
|
||||||
|
Drawable drawable = Drawable::makeImage(image, 1.0f / TilePixels, true, Vec2F());
|
||||||
|
drawable.imagePart().addDirectives(m_imageDirectives, true);
|
||||||
if (m_config->flippable) {
|
if (m_config->flippable) {
|
||||||
auto angleSide = getAngleSide(m_movementController->rotation(), true);
|
auto angleSide = getAngleSide(m_movementController->rotation(), true);
|
||||||
if (angleSide.second == Direction::Left)
|
if (angleSide.second == Direction::Left)
|
||||||
@ -539,7 +541,8 @@ void Projectile::setFrame(int frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String Projectile::drawableFrame() {
|
String Projectile::drawableFrame() {
|
||||||
return strf("{}:{}{}", m_config->image, m_frame, m_imageDirectives);
|
String str = strf("{}:{}{}", m_config->image, m_frame, m_imageSuffix);
|
||||||
|
return m_imageDirectives.addToString(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Projectile::ephemeral() const {
|
bool Projectile::ephemeral() const {
|
||||||
@ -896,7 +899,22 @@ void Projectile::setup() {
|
|||||||
m_acceleration = m_parameters.getFloat("acceleration", m_config->acceleration);
|
m_acceleration = m_parameters.getFloat("acceleration", m_config->acceleration);
|
||||||
m_power = m_parameters.getFloat("power", m_config->power);
|
m_power = m_parameters.getFloat("power", m_config->power);
|
||||||
m_powerMultiplier = m_parameters.getFloat("powerMultiplier", 1.0f);
|
m_powerMultiplier = m_parameters.getFloat("powerMultiplier", 1.0f);
|
||||||
m_imageDirectives = m_parameters.getString("processing", "");
|
{ // it is possible to shove a frame name in processing. I hope nobody actually does this but account for it...
|
||||||
|
String processing = m_parameters.getString("processing", "");
|
||||||
|
auto begin = processing.utf8().find_first_of('?');
|
||||||
|
if (begin == NPos) {
|
||||||
|
m_imageDirectives = "";
|
||||||
|
m_imageSuffix = move(processing);
|
||||||
|
}
|
||||||
|
else if (begin == 0) {
|
||||||
|
m_imageDirectives = move(processing);
|
||||||
|
m_imageSuffix = "";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_imageDirectives = (String)processing.utf8().substr(begin);
|
||||||
|
m_imageSuffix = processing.utf8().substr(0, begin);
|
||||||
|
}
|
||||||
|
}
|
||||||
m_persistentAudioFile = m_parameters.getString("persistentAudio", m_config->persistentAudio);
|
m_persistentAudioFile = m_parameters.getString("persistentAudio", m_config->persistentAudio);
|
||||||
|
|
||||||
m_damageKind = m_parameters.getString("damageKind", m_config->damageKind);
|
m_damageKind = m_parameters.getString("damageKind", m_config->damageKind);
|
||||||
|
@ -137,7 +137,8 @@ private:
|
|||||||
float m_initialSpeed;
|
float m_initialSpeed;
|
||||||
float m_power;
|
float m_power;
|
||||||
float m_powerMultiplier;
|
float m_powerMultiplier;
|
||||||
String m_imageDirectives;
|
Directives m_imageDirectives;
|
||||||
|
String m_imageSuffix;
|
||||||
Json m_damageTeam;
|
Json m_damageTeam;
|
||||||
String m_damageKind;
|
String m_damageKind;
|
||||||
DamageType m_damageType;
|
DamageType m_damageType;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "StarVersion.hpp"
|
#include "StarVersion.hpp"
|
||||||
#include "StarRoot.hpp"
|
#include "StarRoot.hpp"
|
||||||
#include "StarConfiguration.hpp"
|
#include "StarConfiguration.hpp"
|
||||||
|
#include "StarProjectileDatabase.hpp"
|
||||||
#include "StarPlayerStorage.hpp"
|
#include "StarPlayerStorage.hpp"
|
||||||
#include "StarPlayer.hpp"
|
#include "StarPlayer.hpp"
|
||||||
#include "StarPlayerLog.hpp"
|
#include "StarPlayerLog.hpp"
|
||||||
@ -485,7 +486,7 @@ void UniverseClient::stopLua() {
|
|||||||
m_scriptContexts.clear();
|
m_scriptContexts.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UniverseClient::reloadPlayer(Json const& data, Uuid const& uuid, bool resetInterfaces) {
|
bool UniverseClient::reloadPlayer(Json const& data, Uuid const& uuid, bool resetInterfaces, bool showIndicator) {
|
||||||
auto player = mainPlayer();
|
auto player = mainPlayer();
|
||||||
bool playerInWorld = player->inWorld();
|
bool playerInWorld = player->inWorld();
|
||||||
auto world = as<WorldClient>(player->world());
|
auto world = as<WorldClient>(player->world());
|
||||||
@ -497,7 +498,20 @@ bool UniverseClient::reloadPlayer(Json const& data, Uuid const& uuid, bool reset
|
|||||||
if (m_playerReloadPreCallback)
|
if (m_playerReloadPreCallback)
|
||||||
m_playerReloadPreCallback(resetInterfaces);
|
m_playerReloadPreCallback(resetInterfaces);
|
||||||
|
|
||||||
|
ProjectilePtr indicator;
|
||||||
|
|
||||||
if (playerInWorld) {
|
if (playerInWorld) {
|
||||||
|
if (showIndicator) {
|
||||||
|
// EntityCreatePacket for player entities can be pretty big.
|
||||||
|
// We can show a loading projectile to other players while the create packet uploads.
|
||||||
|
auto projectileDb = Root::singleton().projectileDatabase();
|
||||||
|
auto config = projectileDb->projectileConfig("opensb:playerloading");
|
||||||
|
indicator = projectileDb->createProjectile("stationpartsound", config);
|
||||||
|
indicator->setInitialPosition(player->position());
|
||||||
|
indicator->setInitialDirection({ 1.0f, 0.0f });
|
||||||
|
world->addEntity(indicator);
|
||||||
|
}
|
||||||
|
|
||||||
world->removeEntity(player->entityId(), false);
|
world->removeEntity(player->entityId(), false);
|
||||||
} else {
|
} else {
|
||||||
m_respawning = false;
|
m_respawning = false;
|
||||||
@ -518,6 +532,9 @@ bool UniverseClient::reloadPlayer(Json const& data, Uuid const& uuid, bool reset
|
|||||||
|
|
||||||
world->addEntity(player, entityId);
|
world->addEntity(player, entityId);
|
||||||
|
|
||||||
|
if (indicator && indicator->inWorld())
|
||||||
|
world->removeEntity(indicator->entityId(), false);
|
||||||
|
|
||||||
CelestialCoordinate coordinate = m_systemWorldClient->location();
|
CelestialCoordinate coordinate = m_systemWorldClient->location();
|
||||||
player->universeMap()->addMappedCoordinate(coordinate);
|
player->universeMap()->addMappedCoordinate(coordinate);
|
||||||
player->universeMap()->filterMappedObjects(coordinate, m_systemWorldClient->objectKeys());
|
player->universeMap()->filterMappedObjects(coordinate, m_systemWorldClient->objectKeys());
|
||||||
@ -535,7 +552,7 @@ bool UniverseClient::switchPlayer(Uuid const& uuid) {
|
|||||||
if (uuid == mainPlayer()->uuid())
|
if (uuid == mainPlayer()->uuid())
|
||||||
return false;
|
return false;
|
||||||
else if (auto data = m_playerStorage->maybeGetPlayerData(uuid))
|
else if (auto data = m_playerStorage->maybeGetPlayerData(uuid))
|
||||||
return reloadPlayer(*data, uuid, true);
|
return reloadPlayer(*data, uuid, true, true);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ public:
|
|||||||
void startLua();
|
void startLua();
|
||||||
void stopLua();
|
void stopLua();
|
||||||
|
|
||||||
bool reloadPlayer(Json const& data, Uuid const& uuid, bool resetInterfaces = false);
|
bool reloadPlayer(Json const& data, Uuid const& uuid, bool resetInterfaces = false, bool showIndicator = false);
|
||||||
bool switchPlayer(Uuid const& uuid);
|
bool switchPlayer(Uuid const& uuid);
|
||||||
bool switchPlayer(size_t index);
|
bool switchPlayer(size_t index);
|
||||||
bool switchPlayer(String const& name);
|
bool switchPlayer(String const& name);
|
||||||
|
@ -1275,6 +1275,7 @@ void WorldClient::addEntity(EntityPtr const& entity, EntityId entityId) {
|
|||||||
if (entity->clientEntityMode() != ClientEntityMode::ClientSlaveOnly) {
|
if (entity->clientEntityMode() != ClientEntityMode::ClientSlaveOnly) {
|
||||||
entity->init(this, m_entityMap->reserveEntityId(entityId), EntityMode::Master);
|
entity->init(this, m_entityMap->reserveEntityId(entityId), EntityMode::Master);
|
||||||
m_entityMap->addEntity(entity);
|
m_entityMap->addEntity(entity);
|
||||||
|
notifyEntityCreate(entity);
|
||||||
} else {
|
} else {
|
||||||
auto entityFactory = Root::singleton().entityFactory();
|
auto entityFactory = Root::singleton().entityFactory();
|
||||||
m_outgoingPackets.append(make_shared<SpawnEntityPacket>(entity->entityType(), entityFactory->netStoreEntity(entity), entity->writeNetState().first));
|
m_outgoingPackets.append(make_shared<SpawnEntityPacket>(entity->entityType(), entityFactory->netStoreEntity(entity), entity->writeNetState().first));
|
||||||
@ -1358,15 +1359,7 @@ void WorldClient::queueUpdatePackets() {
|
|||||||
if (m_currentStep % m_clientConfig.getInt("worldClientStateUpdateDelta") == 0)
|
if (m_currentStep % m_clientConfig.getInt("worldClientStateUpdateDelta") == 0)
|
||||||
m_outgoingPackets.append(make_shared<WorldClientStateUpdatePacket>(m_clientState.writeDelta()));
|
m_outgoingPackets.append(make_shared<WorldClientStateUpdatePacket>(m_clientState.writeDelta()));
|
||||||
|
|
||||||
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
m_entityMap->forAllEntities([&](EntityPtr const& entity) { notifyEntityCreate(entity); });
|
||||||
if (entity->isMaster() && !m_masterEntitiesNetVersion.contains(entity->entityId())) {
|
|
||||||
// Server was unaware of this entity until now
|
|
||||||
auto firstNetState = entity->writeNetState();
|
|
||||||
m_masterEntitiesNetVersion[entity->entityId()] = firstNetState.second;
|
|
||||||
m_outgoingPackets.append(make_shared<EntityCreatePacket>(entity->entityType(),
|
|
||||||
entityFactory->netStoreEntity(entity), move(firstNetState.first), entity->entityId()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (m_currentStep % m_interpolationTracker.entityUpdateDelta() == 0) {
|
if (m_currentStep % m_interpolationTracker.entityUpdateDelta() == 0) {
|
||||||
auto entityUpdateSet = make_shared<EntityUpdateSetPacket>();
|
auto entityUpdateSet = make_shared<EntityUpdateSetPacket>();
|
||||||
@ -1742,6 +1735,16 @@ void WorldClient::tryGiveMainPlayerItem(ItemPtr item) {
|
|||||||
addEntity(ItemDrop::createRandomizedDrop(spill->descriptor(), m_mainPlayer->position()));
|
addEntity(ItemDrop::createRandomizedDrop(spill->descriptor(), m_mainPlayer->position()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldClient::notifyEntityCreate(EntityPtr const& entity) {
|
||||||
|
if (entity->isMaster() && !m_masterEntitiesNetVersion.contains(entity->entityId())) {
|
||||||
|
// Server was unaware of this entity until now
|
||||||
|
auto firstNetState = entity->writeNetState();
|
||||||
|
m_masterEntitiesNetVersion[entity->entityId()] = firstNetState.second;
|
||||||
|
m_outgoingPackets.append(make_shared<EntityCreatePacket>(entity->entityType(),
|
||||||
|
Root::singleton().entityFactory()->netStoreEntity(entity), move(firstNetState.first), entity->entityId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Vec2I WorldClient::environmentBiomeTrackPosition() const {
|
Vec2I WorldClient::environmentBiomeTrackPosition() const {
|
||||||
if (!inWorld())
|
if (!inWorld())
|
||||||
return {};
|
return {};
|
||||||
|
@ -212,6 +212,8 @@ private:
|
|||||||
void clearWorld();
|
void clearWorld();
|
||||||
void tryGiveMainPlayerItem(ItemPtr item);
|
void tryGiveMainPlayerItem(ItemPtr item);
|
||||||
|
|
||||||
|
void notifyEntityCreate(EntityPtr const& entity);
|
||||||
|
|
||||||
// Queues pending (step based) updates to server,
|
// Queues pending (step based) updates to server,
|
||||||
void queueUpdatePackets();
|
void queueUpdatePackets();
|
||||||
void handleDamageNotifications();
|
void handleDamageNotifications();
|
||||||
|
Loading…
Reference in New Issue
Block a user