diff --git a/src/game/main-urho3d.cc b/src/game/main-urho3d.cc index befb718e5..785160736 100644 --- a/src/game/main-urho3d.cc +++ b/src/game/main-urho3d.cc @@ -713,7 +713,7 @@ void CryptoCityUrho3D::HandleBuy(StringHash eventType, VariantMap& eventData) cmd.buy.y = sy0; cmd.buy.wm1 = sx1 - sx0; cmd.buy.hm1 = sy1 - sy0; - if (map.command(cmd, tmp_n_players, tmp_players)) + if (map.command(cmd, &playerState)) cityMesh->buildMap(); } @@ -745,7 +745,7 @@ void CryptoCityUrho3D::HandleBuildOne(StringHash eventType, VariantMap& eventDat } cmd.push_area.type_ptr = encoded_types; cmd.push_area.type_len = encoded_types_len; - if (map.command(cmd, tmp_n_players, tmp_players)) + if (map.command(cmd, &playerState)) cityMesh->buildMap(); } @@ -764,7 +764,7 @@ void CryptoCityUrho3D::HandleDestroyOne(StringHash eventType, VariantMap& eventD cmd.push_area.dy = sy0 - flag->y0; cmd.push_area.wm1 = sx1 - sx0; cmd.push_area.hm1 = sy1 - sy0; - if (map.command(cmd, tmp_n_players, tmp_players)) + if (map.command(cmd, &playerState)) cityMesh->buildMap(); } diff --git a/src/game/map.cc b/src/game/map.cc index 8a76bda47..2884e44bb 100644 --- a/src/game/map.cc +++ b/src/game/map.cc @@ -6,21 +6,12 @@ #include <stdexcept> #include <algorithm> #include "get_us.h" +#include "cc/cc.h" #include "cc/sqrtint.h" #include "map.h" using namespace Urho3D; -#define STARTING_RADIUS 6 -#define BASE_TILE_BUY_COST 2 -#define BUY_BORDER_SIZE 2 -#define BASE_BLOCK_PLACEMENT_COST 100 -#define BLOCK_PLACEMENT_COST_INCREASE_RATE_INVERSE 1024 -#define BLOCK_POP_COST 0 -#define MIN_BUY_SIDE_SIZE 3 -#define EXPAND_SIZE 32 -#define NEW_FLAG_BASE_COST 99 - BlockMaterial materials[256] = { { @@ -65,31 +56,6 @@ BlockMaterial materials[256] = }, }; -Player tmp_players[] = -{ - { // the game itself - 0, - 0, - "", -#define I (uint32_t)-1 - {I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, }, -#undef I - }, - { - 1, - 1234567, - "test player 1", - {0, 1000, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - }, - { - 2, - 1000, - "test player 2", - {0, 80, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - }, -}; -size_t tmp_n_players = sizeof(tmp_players) / sizeof(tmp_players[0]); - bool encode_single_type(uint8_t src_type, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len) { *encoded_types_len = 0; @@ -103,100 +69,6 @@ bool encode_single_type(uint8_t src_type, uint16_t n_src_types, uint8_t *encoded return true; } -bool encode_types(const uint8_t *src_types, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len) -{ - *encoded_types_len = 0; - while (n_src_types > 0) - { - // find offset of next run > 2 - uint8_t offset = 0; - bool found = false; - while (offset + 2 < n_src_types && offset < 127 - 1) - { - const uint8_t *ptr = src_types + offset; - if (*ptr == *(ptr+1) && *ptr == *(ptr+2)) - { - found = true; - break; - } - ++offset; - } -//printf("offset %u, found %d, n_src_types %u\n", offset, found, n_src_types); - if (!found && offset == 0) - { - if (n_src_types > 2) - { - printf("Bug: found %d, n_src_types %u, offset %u\n", found, n_src_types, offset); - return false; - } - offset = n_src_types; - } - if (offset > 0) - { - uint8_t len = offset; - if (*encoded_types_len >= 65535 - 1 - len) - return false; -//printf("encoding %u list strip\n", len); - encoded_types[++*encoded_types_len - 1] = 0x00 | len; - n_src_types -= len; - while (len--) - encoded_types[++*encoded_types_len - 1] = *src_types++; - } - if (found) - { - // work out next run length - uint8_t len = 1; - while (len < 127 && n_src_types > len && src_types[len] == src_types[0]) - ++len; -//printf("encoding %u rle strip\n", len); - if (*encoded_types_len >= 65535 - 2) - return false; - encoded_types[++*encoded_types_len - 1] = 0x80 | len; - encoded_types[++*encoded_types_len - 1] = src_types[0]; - n_src_types -= len; - src_types += len; - } - } - return true; -} - -bool decode_types(const uint8_t *encoded_types, uint16_t encoded_types_len, uint8_t *dst_types, uint16_t *n_dst_types) -{ - *n_dst_types = 0; - while (encoded_types_len-- > 0) - { - const bool is_rle = (*encoded_types) & 0x80; - uint8_t len = (*encoded_types) & 0x7f; - ++encoded_types; - if (is_rle) - { - if (encoded_types_len < 1) - return false; - uint8_t t = *encoded_types++; - encoded_types_len--; - if (*n_dst_types >= 65535 - len) - return false; - while (len--) - dst_types[++*n_dst_types - 1] = t; - } - else - { - if (encoded_types_len < len) - goto error; - encoded_types_len -= len; - if (*n_dst_types >= 65535 - len) - return false; - while (len--) - dst_types[++*n_dst_types - 1] = *encoded_types++; - } - } - return true; - -error: - *n_dst_types = 0; - return false; -} - void Tile::push(uint8_t type) { if (height == std::numeric_limits<uint16_t>::max()) @@ -387,7 +259,7 @@ bool Flag::check_build_rules(const Tile &t, uint32_t x, uint32_t y, uint16_t hei return true; } -bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len) +bool Flag::push_tiles(PlayerState *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len) { if (px0 < x0 || px1 > x1 || py0 < y0 || py1 > y1) { @@ -396,8 +268,8 @@ bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, } uint8_t decoded_types[65536]; - uint16_t n_decoded_types; - if (!decode_types(type_ptr, type_len, decoded_types, &n_decoded_types)) + uint32_t n_decoded_types; + if (!cc::decode_blocks(type_ptr, type_len, decoded_types, &n_decoded_types)) { printf("Failed to decode types\n"); return false; @@ -413,7 +285,7 @@ bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, uint64_t cost = 0; const uint32_t w = x1 - x0 + 1; uint32_t done = 0; - const uint32_t owner = player->owner; + const uint32_t owner = player->id; uint32_t blocks_needed[256] = {0}; for (uint32_t ty = py0; ty <= py1; ++ty) { @@ -440,9 +312,9 @@ bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, } for (uint32_t idx = 1; idx < 256; ++idx) { - if (blocks_needed[idx] > player->blocks[idx]) + if (blocks_needed[idx] > player->block_balances[idx]) { - printf("Not enough blocks of type %u (%u, needs %u)\n", idx, player->blocks[idx], blocks_needed[idx]); + printf("Not enough blocks of type %u (%u, needs %u)\n", idx, player->block_balances[idx], blocks_needed[idx]); goto undo; } } @@ -459,7 +331,7 @@ bool Flag::push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, player->balance -= cost; for (uint32_t idx = 1; idx < 256; ++idx) - player->blocks[idx] -= blocks_needed[idx]; + player->block_balances[idx] -= blocks_needed[idx]; return true; @@ -481,7 +353,7 @@ undo: return false; } -bool Flag::pop_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1) +bool Flag::pop_tiles(PlayerState *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1) { if (px0 < x0 || px1 > x1 || py0 < y0 || py1 > y1) { @@ -610,14 +482,6 @@ bool Flag::build_predefined(const char *name, uint32_t bx0, uint32_t by0, uint32 return true; } -void TopOfTheWorld::reset() -{ - tallest.owner = 0; - tallest.x = 0; - tallest.y = 0; - tallest.height = 0; -} - Map::Map(uint32_t x, uint32_t y): ox(x), oy(y) { if (x == std::numeric_limits<uint32_t>::max()) @@ -693,9 +557,9 @@ void Map::get_flags(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, std::deq qflags.query(x0, y0, x1, y1, res); } -bool Map::buy(Player *player, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1) +bool Map::buy(PlayerState *player, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1) { - if (!player || !player->owner) + if (!player || !player->id) { printf("Bad player"); return false; @@ -706,7 +570,7 @@ bool Map::buy(Player *player, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1) return false; } - const uint32_t owner = player->owner; + const uint32_t owner = player->id; if (has_flag(x, y, x+wm1, y+hm1)) { printf("Already owned\n"); @@ -740,15 +604,15 @@ bool Map::buy(Player *player, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1) return true; } -bool Map::push_tiles(Player *player, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len) +bool Map::push_tiles(PlayerState *player, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len) { - if (!player || !player->owner) + if (!player || !player->id) { printf("Bad player"); return false; } SharedPtr<Flag> flag = get_flag(flag_id); - if (!flag || flag->owner != player->owner) + if (!flag || flag->owner != player->id) { printf("Not owned\n"); return false; @@ -756,15 +620,15 @@ bool Map::push_tiles(Player *player, uint32_t flag_id, uint8_t dx, uint8_t dy, u return flag->push_tiles(player, flag->x0 + dx, flag->y0 + dy, flag->x0 + dx + wm1, flag->y0 + dy + hm1, min_height, type_ptr, type_len); } -bool Map::pop_tiles(Player *player, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1) +bool Map::pop_tiles(PlayerState *player, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1) { - if (!player || !player->owner) + if (!player || !player->id) { printf("Bad player"); return false; } SharedPtr<Flag> flag = get_flag(flag_id); - if (!flag || flag->owner != player->owner) + if (!flag || flag->owner != player->id) { printf("Not owned\n"); return false; @@ -772,15 +636,14 @@ bool Map::pop_tiles(Player *player, uint32_t flag_id, uint8_t dx, uint8_t dy, ui return flag->pop_tiles(player, flag->x0 + dx, flag->y0 + dy, flag->x0 + dx + wm1, flag->y0 + dy + hm1); } -bool Map::command(const Command &cmd, size_t n_players, Player *players) +bool Map::command(const Command &cmd, PlayerState *player) { - if (cmd.owner == 0 || cmd.owner >= n_players) + if (!player || player->id == 0) { printf("Invalid player\n"); return false; } - Player *player = players + cmd.owner; - if (player->owner != cmd.owner) + if (player->id != cmd.owner) { printf("Inconsistent player\n"); return false; @@ -831,95 +694,3 @@ bool Map::build_predefined(const char *name, uint32_t bx0, uint32_t by0, uint32_ } return flag->build_predefined(name, bx0, by0, bx1, by1); } - -void Map::get_top_of_the_world(TopOfTheWorld &totw) const -{ -#if 0 - totw.reset(); - - const uint32_t w = x1 - x0 + 1; - for (uint32_t y = y0; y <= y1; ++y) - { - for (uint32_t x = x0; x <= x1; ++x) - { - const Tile &t = tiles[(y-y0) * w + x-x0]; - uint32_t owner = t.get_owner(); - if (owner != 0) - { - const uint16_t th = t.get_height(); - if (th > totw.tallest.height) - { - totw.tallest.owner = owner; - totw.tallest.x = x; - totw.tallest.y = y; - totw.tallest.height = th; - } - } - } - } -#endif -} - -void Map::test_encoding(unsigned int seed) -{ - uint8_t raw[65536], encoded[65536], decoded[65536]; - uint16_t encoded_len, decoded_len; - if (seed == 0) - seed = time(NULL); -//seed = 1563281381; - srand(seed); - uint64_t total = 0, bytes = 0; - - const unsigned int n_recover_tests = 100; - const unsigned int n_decode_tests = 10000; - - for (unsigned int i = 0; i < n_recover_tests; ++i) - { - uint16_t len = rand(); - for (int n = 0; n < len; ++n) - { - raw[n] = rand() & 7; - } - if (!encode_types(raw, len, encoded, &encoded_len)) - { - printf("Failed to encode: seed %u, input len %u\n", seed, len); - continue; - } - if (!decode_types(encoded, encoded_len, decoded, &decoded_len)) - { - printf("Failed to decode: seed %u\n", seed); - return; - } - if (decoded_len != len) - { - printf("Decoded len is wrong: seed %u\n", seed); - return; - } - if (memcmp(raw, decoded, len)) - { - printf("Decoded data is wrong: seed %u\n", seed); - return; - } - if (encoded_len > len) - { - //printf("encoded_len (%u) > len (%u): seed %u: %.3f\n", encoded_len, len, seed, 100.0f * encoded_len / (float)len); - } - printf("\r%u/%u ", i, n_recover_tests); fflush(stdout); - total += len; - bytes += encoded_len; - } - printf("\r \r\n"); - printf("Compression: %.3f%%\n", 100.0f * bytes/(float)total); - - for (unsigned int i = 0; i < n_decode_tests; ++i) - { - uint16_t len = rand(); - for (int n = 0; n < len; ++n) - { - raw[n] = rand(); - } - decode_types(raw, len, decoded, &decoded_len); - printf("\r%u/%u ", i, n_decode_tests); fflush(stdout); - } - printf("\r \r\n"); -} diff --git a/src/game/map.h b/src/game/map.h index ca068bd0c..380f12668 100644 --- a/src/game/map.h +++ b/src/game/map.h @@ -6,19 +6,9 @@ #include <map> #include <Urho3D/Container/RefCounted.h> #include <Urho3D/Container/Ptr.h> +#include "player-state.h" #include "quadtree.h" -struct Player -{ - uint32_t owner; - uint64_t balance; - const char *name; - uint32_t blocks[256]; -}; - -extern Player tmp_players[]; -extern size_t tmp_n_players; - struct BlockMaterial { uint8_t type; @@ -41,8 +31,6 @@ struct BlockMaterial extern BlockMaterial materials[256]; bool encode_single_type(uint8_t src_type, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len); -bool encode_types(const uint8_t *src_types, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len); -bool decode_types(const uint8_t *encoded_types, uint16_t encoded_types_len, uint8_t *dst_types, uint16_t *n_dst_types); class Tile { @@ -91,8 +79,8 @@ public: uint64_t get_block_cost_for_height(uint16_t h) const; uint16_t get_tile_height(uint32_t x, uint32_t y) const; - bool push_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len); - bool pop_tiles(Player *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1); + bool push_tiles(PlayerState *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len); + bool pop_tiles(PlayerState *player, uint32_t px0, uint32_t py0, uint32_t px1, uint32_t py1); bool build_predefined(const char *name, uint32_t bx0, uint32_t by0, uint32_t bx1, uint32_t by1); @@ -152,21 +140,6 @@ struct Command }; }; -struct TopOfTheWorld -{ - struct Tallest - { - uint32_t owner; - uint32_t x; - uint32_t y; - uint16_t height; - }; - Tallest tallest; - - TopOfTheWorld() { reset(); } - void reset(); -}; - struct Map { Map(uint32_t x, uint32_t y); @@ -184,11 +157,10 @@ struct Map bool build_predefined(const char *name, uint32_t bx0, uint32_t by0, uint32_t bx1, uint32_t by1); // consensus - bool buy(Player *p, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1); - bool push_tiles(Player *p, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len); - bool pop_tiles(Player *p, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1); - bool command(const Command &cmd, size_t nplayers, Player *players); - void get_top_of_the_world(TopOfTheWorld &totw) const; + bool buy(PlayerState *p, uint32_t x, uint32_t y, uint8_t wm1, uint8_t hm1); + bool push_tiles(PlayerState *p, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1, uint16_t min_height, const uint8_t *type_ptr, uint16_t type_len); + bool pop_tiles(PlayerState *p, uint32_t flag_id, uint8_t dx, uint8_t dy, uint8_t wm1, uint8_t hm1); + bool command(const Command &cmd, PlayerState *player); private: uint32_t allocate_new_flag();