From 02babe17928dc8fbbf490479e1de7b366a2b8315 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sun, 19 Feb 2023 10:22:03 +0100 Subject: [PATCH] Implement secret block & doors --- assets/textures/pack_owner.png | Bin 715 -> 723 bytes src/client/client.cpp | 62 +++++++++++-- src/client/client_packethandler.cpp | 72 ++++++++++++++- src/core/blockmanager.cpp | 7 +- src/core/blockmanager.h | 6 +- src/core/blockmanager_reg.cpp | 135 ++++++++++++++++++++++++++++ src/core/environment.h | 7 -- src/core/packet.h | 2 +- src/core/player.cpp | 31 ++++++- src/core/player.h | 3 +- src/core/types.h | 6 +- src/core/world.cpp | 57 ++++++++---- src/core/world.h | 19 +++- src/gui/gameplay.cpp | 10 +-- src/gui/gameplay.h | 2 +- src/gui/minimap.cpp | 3 +- src/main.cpp | 132 +-------------------------- src/server/database_world.cpp | 2 +- src/server/server.cpp | 29 +++++- src/server/server.h | 2 +- src/server/server_packethandler.cpp | 37 +++++++- src/tests/test_world.cpp | 2 +- 22 files changed, 437 insertions(+), 189 deletions(-) create mode 100644 src/core/blockmanager_reg.cpp diff --git a/assets/textures/pack_owner.png b/assets/textures/pack_owner.png index 2ba542265407ab8c8ce12893334b6c91a774ae12..a2317b1a3624cab761f96d5c76a5e69c57ffb90b 100644 GIT binary patch literal 723 zcmeAS@N?(olHy`uVBq!ia0vp^2|%pC!3-pC$@QiIsm}pEA+A9B|8N9Af3dKzu(7eR zv$Jz>aM;<|IXgRhdU^u=dS!aTDWJ4RNswPK0}DH!kg%+rvZ}V8iH)s)Oj>$Yc1~ew zd38(AglRKo&Ym-O*}C5@*~P%X=cuYs3;d|;1LvMM84~P4EIhh$0 zZs<3Ji_FssD84Hd>aZnuqE^7HvtIuXh%r18;C-;8zD$7m$DdanYz5+H{r$ojrY-x% zI#t%^x%1CNHLt}VRlT3`+>p-x^`*jA%2VRk1ml}IYGU&`lT}`?_jX_iUs>=`F7M>( znS1_+bFyi?s8amt^?hDj{gi};M@ObiF8vu*G&||$9Fd0%j_Pi)Ki=u7T;W~BUBHmF zYo6(fb(|_8?9-l`2|ma_RmStk(%Cmus%sUmY`=u8*cSeRou++pi#jS)qHK?^HDb%( zQnP(+*4{e*;M;d?*4`F*%2)it-(U1M$B+HJecY!Guit<6!|r4|#;A}=`&7ft2Eb@y N@O1TaS?83{1OR~MvGo7| literal 715 zcmV;+0yO=JP)lC# zBl(n(44t%&D4=-YRo-te3R z)_}8S_O0CpX7(F+D`^Cn15St4%XQGH4PeV{BO&6GyCK~)00D3%>U}Q7X=Dd@+KB@* z`wYC>Ys9~r*>Vhio`)6Y6G%!0pchy%vswpgmE-7-nceM3aY?5nElRp3>0m^iB5(tk z28PqT9PdW)2f$Ha5(t2<5Yl&m3qUup2)s!v@!ibvo4|@cj{_yZ{C~HTKIen-0+{)q zc54HYUP)S)^h45`q@R-JBvsrVy821>V=0l{nWVg=LvHy9@|%(ZNn4Uuqe!>%^)HD> zg?c}5*{#1ROICqPzy~kd=OO70B{NPXls=%hN>)XDW=>_(CSP%L% zGT;~R8o2J$BM#!rKwnewaWh+pE98rku1cEq3js;mZW!gj6%887wi_-GX1#qe#%b8) zOKCGkVo^NggC~Ide(BKT>h}0@R(EAL{r3nkZf5Ue&OL{L+rX`m*Ym)bpXzpEBOY-I x8*Ct6>Etxl&b;;kZ3n|~4|;|S88Yk%`~h7({kyNFnu`Dc002ovPDHLkV1i*yO%wnC diff --git a/src/client/client.cpp b/src/client/client.cpp index c4ebf7a..d813f1b 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -30,9 +30,6 @@ Client::Client(ClientStartData &init) } m_nickname = init.nickname; - - for (auto &k : m_keys) - k = Environment::Key(); } Client::~Client() @@ -93,11 +90,66 @@ void Client::step(float dtime) // Run physics engine if (world.ptr()) { + std::set triggered_blocks; SimpleLock lock(m_players_lock); for (auto it : m_players) { - it.second->step(dtime); + if (it.first == m_my_peer_id) { + it.second->triggered_blocks = &triggered_blocks; + it.second->step(dtime); + it.second->triggered_blocks = nullptr; + } else { + it.second->step(dtime); + } + } + + auto &meta = world->getMeta(); + for (auto &kdata : meta.keys) { + kdata.step(dtime); + } + + // Process triggers + bool trigger_event = false; + Packet pkt; + pkt.write(Packet2Server::TriggerBlocks); + + for (blockpos_t bp : triggered_blocks) { + Block b; + if (!world->getBlock(bp, &b)) + continue; + + switch (b.id) { + case Block::ID_KEY_R: + case Block::ID_KEY_G: + case Block::ID_KEY_B: + { + int key_id = b.id - Block::ID_KEY_R; + auto &kdata = meta.keys[key_id]; + if (kdata.trigger(-1.0f)) { + pkt.write(bp.X); + pkt.write(bp.Y); + } + } + break; + case Block::ID_SECRET: + if (!b.param1) { + b.param1 = true; + world->setBlock(bp, b); + trigger_event = true; + } + break; + } + } // for + + if (pkt.size() > 4) { + pkt.write(BLOCKPOS_INVALID); // end + + m_con->send(0, 1, pkt); + } + + if (trigger_event) { + GameEvent e(GameEvent::C2G_MAP_UPDATE); + sendNewEvent(e); } - //printf("Client players: %zu\n", m_players.size()); } } diff --git a/src/client/client_packethandler.cpp b/src/client/client_packethandler.cpp index 15fdeed..0244375 100644 --- a/src/client/client_packethandler.cpp +++ b/src/client/client_packethandler.cpp @@ -155,7 +155,6 @@ void Client::pkt_Leave(Packet &pkt) sendNewEvent(e); } - delete player; if (peer_id == m_my_peer_id) { for (auto it : m_players) { @@ -163,18 +162,26 @@ void Client::pkt_Leave(Packet &pkt) } m_players.clear(); + // Keep myself in the list + m_players.emplace(peer_id, player); + player->setWorld(nullptr); + m_state = ClientState::LobbyIdle; GameEvent e(GameEvent::C2G_LEAVE); sendNewEvent(e); + } else { + delete player; } - } void Client::pkt_SetPosition(Packet &pkt) { SimpleLock lock(m_players_lock); + bool is_respawn = pkt.read(); + bool my_player_affected = false; + while (true) { peer_t peer_id = pkt.read(); if (!peer_id) @@ -189,6 +196,23 @@ void Client::pkt_SetPosition(Packet &pkt) player->pos = pos; player->vel = core::vector2df(); } + + if (peer_id == m_my_peer_id) + my_player_affected = true; + } + + if (!is_respawn || !my_player_affected) + return; + + LocalPlayer *player = getPlayerNoLock(m_my_peer_id); + auto out = player->getWorld()->getBlocks(Block::ID_SECRET, [](Block &b) -> bool { + b.param1 = 0; + return true; + }); + + if (!out.empty()) { + GameEvent e(GameEvent::C2G_MAP_UPDATE); + sendNewEvent(e); } } @@ -266,7 +290,33 @@ void Client::pkt_PlaceBlock(Packet &pkt) void Client::pkt_Key(Packet &pkt) { - // ?? + SimpleLock lock(m_players_lock); + LocalPlayer *player = getPlayerNoLock(m_my_peer_id); + + bid_t key_id = pkt.read(); + bool state = pkt.read(); + + bid_t block_id = 0; + switch (key_id) { + case Block::ID_KEY_R: + case Block::ID_KEY_G: + case Block::ID_KEY_B: + block_id = key_id - Block::ID_KEY_R + Block::ID_DOOR_R; + break; + default: + // Unknown key + return; + }; + + auto out = player->getWorld()->getBlocks(block_id, [state](Block &b) -> bool { + b.param1 = state; + return true; + }); + + if (!out.empty()) { + GameEvent e(GameEvent::C2G_MAP_UPDATE); + sendNewEvent(e); + } } void Client::pkt_GodMode(Packet &pkt) @@ -281,6 +331,22 @@ void Client::pkt_GodMode(Packet &pkt) player->godmode = state; player->acc = core::vector2df(); } + if (peer_id == m_my_peer_id) { + auto out = player->getWorld()->getBlocks(Block::ID_SECRET, [state](Block &b) -> bool { + if (state) + b.param1++; + else if (b.param1) + b.param1--; + else + return false; + return true; + }); + + if (!out.empty()) { + GameEvent e(GameEvent::C2G_MAP_UPDATE); + sendNewEvent(e); + } + } } void Client::pkt_Deprecated(Packet &pkt) diff --git a/src/core/blockmanager.cpp b/src/core/blockmanager.cpp index b4603b4..f5653e8 100644 --- a/src/core/blockmanager.cpp +++ b/src/core/blockmanager.cpp @@ -15,6 +15,9 @@ BlockTile BlockProperties::getTile(const Block b) const case BlockTileCondition::None: return tiles[0]; } + + // Not reachable + return tiles[0]; } BlockProperties::BlockProperties(BlockDrawType type) @@ -150,10 +153,11 @@ void BlockManager::populateTextures(video::IVideoDriver *driver) printf("BlockManager: Registered textures of %d blocks in %zu packs\n", count, m_packs.size()); } -BlockProperties *BlockManager::getProps(bid_t block_id) +const BlockProperties *BlockManager::getProps(bid_t block_id) const { if (block_id >= m_props.size()) return nullptr; + return m_props[block_id]; } @@ -288,4 +292,3 @@ u32 BlockManager::getBlockColor(const BlockTile tile) const return color.color; } - diff --git a/src/core/blockmanager.h b/src/core/blockmanager.h index 0533794..135c224 100644 --- a/src/core/blockmanager.h +++ b/src/core/blockmanager.h @@ -51,6 +51,7 @@ struct BlockPack { struct BlockTile { BlockDrawType type = BlockDrawType::Invalid; + bool have_alpha = false; // false: use BlockDrawType video::ITexture *texture = nullptr; u8 texture_offset = 0; // e.g. when specifying a material }; @@ -60,6 +61,7 @@ struct BlockProperties { BlockPack *pack = nullptr; + bool trigger_on_touch = false; u32 color = 0; // minimap BlockTile tiles[2]; // normal, active @@ -82,10 +84,12 @@ class BlockManager { BlockManager(); ~BlockManager(); + void doPackRegistration(); + void registerPack(BlockPack *pack); void populateTextures(video::IVideoDriver *driver); - BlockProperties *getProps(bid_t block_id); + const BlockProperties *getProps(bid_t block_id) const; BlockPack *getPack(const std::string &name); const std::vector &getPacks() { return m_packs; } video::ITexture *getMissingTexture() { return m_missing_texture; } diff --git a/src/core/blockmanager_reg.cpp b/src/core/blockmanager_reg.cpp new file mode 100644 index 0000000..dc24934 --- /dev/null +++ b/src/core/blockmanager_reg.cpp @@ -0,0 +1,135 @@ +#include "blockmanager.h" +#include "player.h" + + +// -------------- Block registrations ------------- + + +static BP_STEP_CALLBACK(step_arrow_left) +{ + player.acc.X -= Player::GRAVITY_NORMAL; +} + +static BP_STEP_CALLBACK(step_arrow_up) +{ + player.acc.Y -= Player::GRAVITY_NORMAL; +} + +static BP_STEP_CALLBACK(step_arrow_right) +{ + player.acc.X += Player::GRAVITY_NORMAL; +} + +static BP_STEP_CALLBACK(step_arrow_none) +{ +} + +static BP_COLLIDE_CALLBACK(onCollide_b10_bouncy) +{ + if (dir.X) { + player.vel.X *= -0.4f; + } else if (dir.Y) { + player.vel.Y *= -1.5f; + } + return false; +} + +void BlockManager::doPackRegistration() +{ + { + BlockPack *pack = new BlockPack("basic"); + pack->default_type = BlockDrawType::Solid; + pack->block_ids = { 9, 10, 11, 12, 13, 14, 15 }; + g_blockmanager->registerPack(pack); + } + + { + BlockPack *pack = new BlockPack("doors"); + pack->default_type = BlockDrawType::Solid; + pack->block_ids = { Block::ID_DOOR_R, Block::ID_DOOR_G, Block::ID_DOOR_B }; + g_blockmanager->registerPack(pack); + + for (bid_t id : pack->block_ids) { + auto props = m_props[id]; + props->condition = BlockTileCondition::NotZero; + props->tiles[1].type = BlockDrawType::Action; + props->tiles[1].texture_offset = 3; + } + } + + { + BlockPack *pack = new BlockPack("factory"); + pack->default_type = BlockDrawType::Solid; + pack->block_ids = { 45, 46, 47, 48, 49 }; + g_blockmanager->registerPack(pack); + } + + { + BlockPack *pack = new BlockPack("action"); + pack->default_type = BlockDrawType::Action; + pack->block_ids = { 0, 1, 2, 3, 4 }; + g_blockmanager->registerPack(pack); + + m_props[1]->step = step_arrow_left; + m_props[2]->step = step_arrow_up; + m_props[3]->step = step_arrow_right; + m_props[4]->step = step_arrow_none; + } + + { + BlockPack *pack = new BlockPack("keys"); + pack->default_type = BlockDrawType::Action; + pack->block_ids = { Block::ID_KEY_R, Block::ID_KEY_G, Block::ID_KEY_B }; + g_blockmanager->registerPack(pack); + + for (bid_t id : pack->block_ids) + m_props[id]->trigger_on_touch = true; + } + + // For testing. bouncy blue basic block + m_props[10]->onCollide = onCollide_b10_bouncy; + + { + // Spawn block only (for now) + BlockPack *pack = new BlockPack("owner"); + pack->default_type = BlockDrawType::Action; + pack->block_ids = { Block::ID_SPAWN, Block::ID_SECRET }; + g_blockmanager->registerPack(pack); + + auto props = m_props[Block::ID_SECRET]; + props->trigger_on_touch = true; + props->condition = BlockTileCondition::NotZero; + props->tiles[0].type = BlockDrawType::Solid; + props->tiles[0].have_alpha = true; + props->tiles[1].type = BlockDrawType::Solid; + props->tiles[1].texture_offset = 1; + } + + // Decoration + { + BlockPack *pack = new BlockPack("spring"); + pack->default_type = BlockDrawType::Decoration; + pack->block_ids = { 233, 234, 235, 236, 237, 238, 239, 240 }; + g_blockmanager->registerPack(pack); + } + + // Backgrounds + { + // "basic" or "dark" + BlockPack *pack = new BlockPack("simple"); + pack->default_type = BlockDrawType::Background; + pack->block_ids = { 500, 501, 502, 503, 504, 505, 506 }; + g_blockmanager->registerPack(pack); + } + +/* + Key RGB: 6 + Door RGB: 23 + Gate RGB: 26 + Coin: 100 + Coin door: 43 + Spawn: 255 + Secret (invisible): 50 +*/ +} + diff --git a/src/core/environment.h b/src/core/environment.h index 75a8bd1..9c60636 100644 --- a/src/core/environment.h +++ b/src/core/environment.h @@ -17,11 +17,4 @@ class Environment : public PacketProcessor { std::mutex m_players_lock; std::map m_players; - - struct Key { - // Client: cooldown until next sending - // Server: time until disable - float cooldown = 0; - bool active = false; - } m_keys[3]; }; diff --git a/src/core/packet.h b/src/core/packet.h index 78bdbb6..9299dd3 100644 --- a/src/core/packet.h +++ b/src/core/packet.h @@ -77,7 +77,7 @@ enum class Packet2Server : uint16_t { Move, Chat, PlaceBlock, - TriggerBlock, // key/kill ? + TriggerBlocks, // key/kill ? GodMode, MAX_END }; diff --git a/src/core/player.cpp b/src/core/player.cpp index f5688ac..d9f50ca 100644 --- a/src/core/player.cpp +++ b/src/core/player.cpp @@ -7,6 +7,10 @@ constexpr float DISTANCE_STEP = 0.4f; // absolute max is 0.5f +Player::~Player() +{ +} + void Player::setWorld(World *world) { @@ -21,6 +25,8 @@ void Player::setWorld(World *world) pos = core::vector2df(); vel = core::vector2df(); acc = core::vector2df(); + + m_last_pos = blockpos_t(-1, -1); } World *Player::getWorld() @@ -142,6 +148,19 @@ void Player::stepInternal(float dtime) // Evaluate center position blockpos_t bp(pos.X + 0.5f, pos.Y + 0.5f); + if (triggered_blocks && bp != m_last_pos) { + Block block; + m_world->getBlock(bp, &block); + + auto props = g_blockmanager->getProps(block.id); + if (props && props->trigger_on_touch) { + if (bp != m_last_pos) { + triggered_blocks->emplace(bp); + } + } + m_last_pos = bp; + } + if (!godmode) { if (!stepCollisions(dtime)) return; @@ -169,7 +188,7 @@ void Player::stepInternal(float dtime) { // Stokes friction to stop movement after releasing keys - const float coeff_s = godmode ? 1.5f : 2.0f; // Stokes + const float coeff_s = godmode ? 1.5f : 4.0f; // Stokes if (std::fabs(acc.X) < 0.01f && !m_controls.dir.X) acc.X += -coeff_s * vel.X; if (std::fabs(acc.Y) < 0.01f && !m_controls.dir.Y) @@ -242,11 +261,11 @@ bool Player::stepCollisions(float dtime) return true; } - void Player::collideWith(float dtime, int x, int y) { Block b; - bool ok = m_world->getBlock(blockpos_t(x, y), &b); + blockpos_t bp(x, y); + bool ok = m_world->getBlock(bp, &b); if (!ok) return; @@ -271,6 +290,9 @@ void Player::collideWith(float dtime, int x, int y) if (dir.Y) m_collision.Y = dir.Y; if (!props->onCollide || props->onCollide(*this, dir)) { + if (triggered_blocks && props->trigger_on_touch) + triggered_blocks->emplace(bp); + vel.Y = 0; } } else { @@ -279,6 +301,9 @@ void Player::collideWith(float dtime, int x, int y) if (dir.X) m_collision.X = dir.X; if (!props->onCollide || props->onCollide(*this, dir)) { + if (triggered_blocks && props->trigger_on_touch) + triggered_blocks->emplace(bp); + vel.X = 0; } } diff --git a/src/core/player.h b/src/core/player.h index 410c8e5..a0983de 100644 --- a/src/core/player.h +++ b/src/core/player.h @@ -23,7 +23,7 @@ struct PlayerControls { class Player { public: - virtual ~Player() {} + virtual ~Player(); void setWorld(World *world); World *getWorld(); @@ -81,4 +81,5 @@ class Player { core::vector2d m_collision; float m_jump_cooldown = 0; + blockpos_t m_last_pos; }; diff --git a/src/core/types.h b/src/core/types.h index 395931c..8acf802 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -19,13 +19,17 @@ namespace irr { typedef core::vector2d blockpos_t; typedef uint16_t bid_t; -constexpr bid_t BLOCKID_INVALID = UINT16_MAX; +constexpr u16 BLOCKPOS_INVALID = UINT16_MAX; struct Block { enum BlockIDs : bid_t { + ID_KEY_R = 6, + ID_KEY_G, + ID_KEY_B, ID_DOOR_R = 23, ID_DOOR_G, ID_DOOR_B, + ID_SECRET = 50, ID_SPAWN = 255, ID_INVALID = UINT16_MAX }; diff --git a/src/core/world.cpp b/src/core/world.cpp index 313bf27..f5c3b2a 100644 --- a/src/core/world.cpp +++ b/src/core/world.cpp @@ -12,7 +12,7 @@ void WorldMeta::readCommon(Packet &pkt) plays = pkt.read(); } -void WorldMeta::writeCommon(Packet &pkt) +void WorldMeta::writeCommon(Packet &pkt) const { pkt.writeStr16(title); pkt.writeStr16(owner); @@ -63,6 +63,34 @@ void WorldMeta::writePlayerFlags(Packet &pkt) const pkt.write(false); // end } +bool WorldMeta::Key::trigger(float refill) +{ + bool changed = !active; + + if (refill < 0) { + // No re-filling if active + if (!active) + cooldown = -refill; + } else { + // Refill regardless + cooldown = refill; + } + active = true; + return changed; +} + + +bool WorldMeta::Key::step(float dtime) +{ + if (cooldown > 0) + cooldown -= dtime; + if (cooldown <= 0 && active) { + active = false; + return true; + } + return false; +} + // -------------- World class ------------- @@ -223,33 +251,26 @@ bool World::updateBlock(const BlockUpdate bu) return false; id_ref = new_id; + if (!is_background) + ref.param1 = 0; + return true; } -std::vector World::getBlocks(bid_t block_id) const +std::vector World::getBlocks(bid_t block_id, std::function callback) const { std::vector found; - found.reserve(std::hypot(m_size.X, m_size.Y) * 10); + found.reserve(std::hypot(m_size.X, m_size.Y) * 2); - for (size_t y = 0; y < m_size.Y; ++y) - for (size_t x = 0; x < m_size.X; ++x) { - blockpos_t pos(x, y); - if (getBlockRefNoCheck(pos).id == block_id) - found.emplace_back(pos); - } - - return found; -} - -void World::setParam1(bid_t block_id, u8 param1) -{ for (size_t y = 0; y < m_size.Y; ++y) for (size_t x = 0; x < m_size.X; ++x) { blockpos_t pos(x, y); Block &b = getBlockRefNoCheck(pos); - if (b.id == block_id) - b.param1 = param1; + if (b.id == block_id) { + if (!callback || callback(b)) + found.emplace_back(pos); + } } + return found; } - diff --git a/src/core/world.h b/src/core/world.h index dbf32cc..28dcb50 100644 --- a/src/core/world.h +++ b/src/core/world.h @@ -40,7 +40,7 @@ struct BlockUpdateHash { struct WorldMeta { // For networking void readCommon(Packet &pkt); - void writeCommon(Packet &pkt); + void writeCommon(Packet &pkt) const; const std::string id; std::string title; @@ -57,6 +57,19 @@ struct WorldMeta { void readPlayerFlags(Packet &pkt); void writePlayerFlags(Packet &pkt) const; std::map player_flags; + + // Activated keys + struct Key { + // refill < 0: restart counting only when expired + // refill >= 0: restart counting + bool trigger(float refill); + bool step(float dtime); + + // Client: cooldown until next sending + // Server: time until disable + float cooldown = 0; + bool active = false; + } keys[3] = {}; }; @@ -90,8 +103,8 @@ class World : public IReferenceCounted { bool setBlock(blockpos_t pos, const Block block); bool updateBlock(const BlockUpdate bu); - std::vector getBlocks(bid_t block_id) const; - void setParam1(bid_t block_id, u8 param1); + // Result is added when callback is nullptr or returns true + std::vector getBlocks(bid_t block_id, std::function callback) const; blockpos_t getSize() const { return m_size; } const WorldMeta &getMeta() const { return m_meta; } diff --git a/src/gui/gameplay.cpp b/src/gui/gameplay.cpp index 938538e..e14dc52 100644 --- a/src/gui/gameplay.cpp +++ b/src/gui/gameplay.cpp @@ -286,7 +286,7 @@ bool SceneGameplay::OnEvent(const SEvent &e) bool l_pressed = e.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN; // Place bid=0 bool r_pressed = e.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN; - if (!((m_may_drag_draw && m_drag_draw_block != BLOCKID_INVALID) || l_pressed || r_pressed)) + if (!((m_may_drag_draw && m_drag_draw_block != Block::ID_INVALID) || l_pressed || r_pressed)) break; blockpos_t bp; @@ -321,7 +321,7 @@ bool SceneGameplay::OnEvent(const SEvent &e) bu.id = m_drag_draw_block; if (!m_may_drag_draw) - m_drag_draw_block = BLOCKID_INVALID; + m_drag_draw_block = Block::ID_INVALID; m_gui->getClient()->updateBlock(bu); return true; @@ -346,7 +346,7 @@ bool SceneGameplay::OnEvent(const SEvent &e) break; case EMIE_LMOUSE_LEFT_UP: case EMIE_RMOUSE_LEFT_UP: - m_drag_draw_block = BLOCKID_INVALID; + m_drag_draw_block = Block::ID_INVALID; break; default: break; } @@ -672,7 +672,7 @@ bool SceneGameplay::assignBlockTexture(const BlockTile tile, scene::ISceneNode * return true; } - if (tile.type == BlockDrawType::Action) + if (tile.type == BlockDrawType::Action || tile.have_alpha) mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; else if (tile.type == BlockDrawType::Decoration) mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; @@ -729,7 +729,7 @@ void SceneGameplay::updatePlayerlist() { rect.UpperLeftCorner.Y = 5; rect.LowerRightCorner.X += 200; - auto meta = world->getMeta(); + const auto &meta = world->getMeta(); std::string src_text; src_text.append("ID: " + meta.id); src_text.append("\r\nOwner: " + meta.owner); diff --git a/src/gui/gameplay.h b/src/gui/gameplay.h index 310b90e..a40bf84 100644 --- a/src/gui/gameplay.h +++ b/src/gui/gameplay.h @@ -66,7 +66,7 @@ class SceneGameplay : public SceneHandler { // Statis indicators for mouse inputs bool m_may_drag_draw = true; // permission: free drawing - bid_t m_drag_draw_block = BLOCKID_INVALID; // drawing mode + bid_t m_drag_draw_block = Block::ID_INVALID; // drawing mode bool m_erase_mode = false; // removes the pointed block : shift down bool m_ignore_keys = false; // ignore key inputs e.g. when typing diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index 2cd5a58..61970b1 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -65,7 +65,8 @@ void SceneMinimap::step(float dtime) auto props = g_blockmanager->getProps(b.id); video::SColor color(0xFFFF0000); // default red if (props) { - if (props->getTile(b).type != BlockDrawType::Solid) + auto tile = props->getTile(b); + if (tile.have_alpha || tile.type != BlockDrawType::Solid) break; color = props->color; } diff --git a/src/main.cpp b/src/main.cpp index 2556ed4..88ec1ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,7 @@ void sleep_ms(long delay) std::this_thread::sleep_for(std::chrono::milliseconds(delay)); } -const char *VERSION_STRING = "OpenEdits v1.0.4-dev" +const char *VERSION_STRING = "OpenEdits v1.0.5-dev" #ifdef NDEBUG " (Release)" #else @@ -27,141 +27,13 @@ static void exit_cleanup() } - -static BP_STEP_CALLBACK(step_arrow_left) -{ - player.acc.X -= Player::GRAVITY_NORMAL; -} - -static BP_STEP_CALLBACK(step_arrow_up) -{ - player.acc.Y -= Player::GRAVITY_NORMAL; -} - -static BP_STEP_CALLBACK(step_arrow_right) -{ - player.acc.X += Player::GRAVITY_NORMAL; -} - -static BP_STEP_CALLBACK(step_arrow_none) -{ -} - -static BP_STEP_CALLBACK(step_key) -{ - if (player.triggered_blocks) - player.triggered_blocks->emplace(pos); -} - -static BP_COLLIDE_CALLBACK(onCollide_b10_bouncy) -{ - if (dir.X) { - player.vel.X *= -0.4f; - } else if (dir.Y) { - player.vel.Y *= -1.5f; - } - return false; -} - -static void register_packs() -{ - { - BlockPack *pack = new BlockPack("basic"); - pack->default_type = BlockDrawType::Solid; - pack->block_ids = { 9, 10, 11, 12, 13, 14, 15 }; - g_blockmanager->registerPack(pack); - } - - { - BlockPack *pack = new BlockPack("doors"); - pack->default_type = BlockDrawType::Solid; - pack->block_ids = { Block::ID_DOOR_R, Block::ID_DOOR_G, Block::ID_DOOR_B }; - g_blockmanager->registerPack(pack); - - for (int i = Block::ID_DOOR_R; i <= Block::ID_DOOR_B; ++i) { - auto props = g_blockmanager->getProps(i); - props->condition = BlockTileCondition::NotZero; - props->tiles[1].type = BlockDrawType::Action; - props->tiles[1].texture_offset = 3; - } - } - - { - BlockPack *pack = new BlockPack("factory"); - pack->default_type = BlockDrawType::Solid; - pack->block_ids = { 45, 46, 47, 48, 49 }; - g_blockmanager->registerPack(pack); - } - - { - BlockPack *pack = new BlockPack("action"); - pack->default_type = BlockDrawType::Action; - pack->block_ids = { 0, 1, 2, 3, 4 }; - g_blockmanager->registerPack(pack); - - g_blockmanager->getProps(1)->step = step_arrow_left; - g_blockmanager->getProps(2)->step = step_arrow_up; - g_blockmanager->getProps(3)->step = step_arrow_right; - g_blockmanager->getProps(4)->step = step_arrow_none; - } - - { - BlockPack *pack = new BlockPack("keys"); - pack->default_type = BlockDrawType::Action; - pack->block_ids = { 6, 7, 8 }; - g_blockmanager->registerPack(pack); - - g_blockmanager->getProps(6)->step = step_key; - g_blockmanager->getProps(7)->step = step_key; - g_blockmanager->getProps(8)->step = step_key; - } - - // For testing. bouncy blue basic block - g_blockmanager->getProps(10)->onCollide = onCollide_b10_bouncy; - - { - // Spawn block only (for now) - BlockPack *pack = new BlockPack("owner"); - pack->default_type = BlockDrawType::Action; - pack->block_ids = { Block::ID_SPAWN }; - g_blockmanager->registerPack(pack); - } - - // Decoration - { - BlockPack *pack = new BlockPack("spring"); - pack->default_type = BlockDrawType::Decoration; - pack->block_ids = { 233, 234, 235, 236, 237, 238, 239, 240 }; - g_blockmanager->registerPack(pack); - } - - // Backgrounds - { - // "basic" or "dark" - BlockPack *pack = new BlockPack("simple"); - pack->default_type = BlockDrawType::Background; - pack->block_ids = { 500, 501, 502, 503, 504, 505, 506 }; - g_blockmanager->registerPack(pack); - } - -/* - Key RGB: 6 - Door RGB: 23 - Gate RGB: 26 - Coin: 100 - Coin door: 43 - Spawn: 255 - Secret (invisible): 50 -*/ -} - int main(int argc, char *argv[]) { atexit(exit_cleanup); srand(time(nullptr)); g_blockmanager = new BlockManager(); - register_packs(); + g_blockmanager->doPackRegistration(); if (argc >= 2) { if (strcmp(argv[1], "--version") == 0) { diff --git a/src/server/database_world.cpp b/src/server/database_world.cpp index 07e4e15..edcb9bd 100644 --- a/src/server/database_world.cpp +++ b/src/server/database_world.cpp @@ -144,7 +144,7 @@ bool DatabaseWorld::save(const World *world) sqlite3_step(m_stmt_begin); sqlite3_reset(m_stmt_begin); - auto &meta = world->getMeta(); + const auto &meta = world->getMeta(); auto s = m_stmt_write; custom_bind_string(s, 1, meta.id); diff --git a/src/server/server.cpp b/src/server/server.cpp index b1482d3..46f0640 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -67,11 +67,14 @@ void Server::step(float dtime) // always player lock first, world lock after. SimpleLock players_lock(m_players_lock); + std::set worlds; for (auto p : m_players) { auto world = p.second->getWorld(); if (!world) continue; + worlds.emplace(world); + auto &queue = world->proc_queue; if (queue.empty()) continue; @@ -111,6 +114,29 @@ void Server::step(float dtime) } } + for (World *world : worlds) { + auto &meta = world->getMeta(); + + for (auto &kdata : meta.keys) { + if (kdata.step(dtime)) { + // Disable keys + + kdata.active = false; + bid_t block_id = (&kdata - meta.keys) + Block::ID_KEY_R; + Packet out; + out.write(Packet2Client::Key); + out.write(block_id); + out.write(false); + + for (auto it : m_players) { + if (it.second->getWorld() != world) + continue; + + m_con->send(it.first, 0, out); + } + } + } + } // No player physics (yet?) } @@ -213,7 +239,7 @@ void Server::processPacket(peer_t peer_id, Packet &pkt) void Server::respawnPlayer(Player *player, bool send_packet) { - auto blocks = player->getWorld()->getBlocks(Block::ID_SPAWN); + auto blocks = player->getWorld()->getBlocks(Block::ID_SPAWN, nullptr); if (blocks.empty()) { player->pos = core::vector2df(); @@ -232,6 +258,7 @@ void Server::respawnPlayer(Player *player, bool send_packet) Packet pkt; pkt.write(Packet2Client::SetPosition); + pkt.write(true); pkt.write(player->peer_id); pkt.write(player->pos.X); pkt.write(player->pos.Y); diff --git a/src/server/server.h b/src/server/server.h index 2e7b2bf..442768e 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -37,7 +37,7 @@ class Server : public Environment { void pkt_Move(peer_t peer_id, Packet &pkt); void pkt_Chat(peer_t peer_id, Packet &pkt); void pkt_PlaceBlock(peer_t peer_id, Packet &pkt); - void pkt_TriggerBlock(peer_t peer_id, Packet &pkt); + void pkt_TriggerBlocks(peer_t peer_id, Packet &pkt); void pkt_GodMode(peer_t peer_id, Packet &pkt); void pkt_Deprecated(peer_t peer_id, Packet &pkt); diff --git a/src/server/server_packethandler.cpp b/src/server/server_packethandler.cpp index 13ace3b..e13539e 100644 --- a/src/server/server_packethandler.cpp +++ b/src/server/server_packethandler.cpp @@ -16,7 +16,7 @@ const ServerPacketHandler Server::packet_actions[] = { { RemotePlayerState::WorldPlay, &Server::pkt_Move }, // 5 { RemotePlayerState::WorldPlay, &Server::pkt_Chat }, { RemotePlayerState::WorldPlay, &Server::pkt_PlaceBlock }, - { RemotePlayerState::WorldPlay, &Server::pkt_TriggerBlock }, + { RemotePlayerState::WorldPlay, &Server::pkt_TriggerBlocks }, { RemotePlayerState::WorldPlay, &Server::pkt_GodMode }, { RemotePlayerState::Invalid, 0 } // 10 }; @@ -101,7 +101,7 @@ void Server::pkt_GetLobby(peer_t peer_id, Packet &) worlds.insert(&demo); for (auto world : worlds) { - auto meta = world->getMeta(); + const auto &meta = world->getMeta(); if (!meta.is_public) continue; @@ -312,8 +312,39 @@ void Server::pkt_PlaceBlock(peer_t peer_id, Packet &pkt) } } -void Server::pkt_TriggerBlock(peer_t peer_id, Packet &pkt) +void Server::pkt_TriggerBlocks(peer_t peer_id, Packet &pkt) { + RemotePlayer *player = getPlayerNoLock(peer_id); + auto world = player->getWorld(); + auto &meta = world->getMeta(); + + while (true) { + blockpos_t pos; + pkt.read(pos.X); + if (pos.X == BLOCKPOS_INVALID) + break; + pkt.read(pos.Y); + + Block b; + world->getBlock(pos, &b); + switch (b.id) { + case Block::ID_KEY_R: + case Block::ID_KEY_G: + case Block::ID_KEY_B: + { + int key_id = b.id - Block::ID_KEY_R; + auto &kdata = meta.keys[key_id]; + if (kdata.trigger(5.0f)) { + Packet out; + out.write(Packet2Client::Key); + out.write(b.id); + out.write(kdata.active); + broadcastInWorld(player, 1, out); + } + } + break; + } + } } void Server::pkt_GodMode(peer_t peer_id, Packet &pkt) diff --git a/src/tests/test_world.cpp b/src/tests/test_world.cpp index 86c6450..9c9774a 100644 --- a/src/tests/test_world.cpp +++ b/src/tests/test_world.cpp @@ -43,7 +43,7 @@ void unittest_world() // Invalid block ID BlockUpdate bu; bu.pos = blockpos_t(1, 1); - bu.id = BLOCKID_INVALID; + bu.id = Block::ID_INVALID; CHECK(!w.updateBlock(bu)) // Background on empty foreground