Merge branch 'login' (read more)
This branch was originally intended to rewrite the login system, but I've discovered some serious problems that could not wait. See the previous commit for more information. Hopefully I can get back to this soon. I believe this version deserves a new release tag.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include "vector2.hpp"
|
||||
#include "sprite_sheet.hpp"
|
||||
|
||||
//TODO: correct the PlayerCharacter class and it's movement system
|
||||
class PlayerCharacter {
|
||||
public:
|
||||
enum class Direction {
|
||||
|
||||
+19
-61
@@ -404,76 +404,34 @@ void InWorld::RequestRegion(int x, int y) {
|
||||
//Utilities
|
||||
//-------------------------
|
||||
|
||||
int InWorld::CheckBufferDistance(Region* const region) {
|
||||
/* TODO: Remove InWorld::CheckBufferDistance(), and replace it with a simpler system
|
||||
* DOCUMENTATION
|
||||
* This algorithm is extremely complex and involed, but initial tests show
|
||||
* that it gives the right answers. The purpose is to determine how far off screen
|
||||
* a certain region is, so that it can be unloaded when necessary.
|
||||
*
|
||||
* If the region is actually onscreen, then there's no reason to run the rest, so
|
||||
* the algorithm corrects for the camera's location, before checking the bounds of
|
||||
* the screen.
|
||||
*
|
||||
* The next part is tricky. If X or Y is negative, then it is divided by the
|
||||
* graphical size of the regions, resulting in a usable integer, representing how
|
||||
* far from the screen it is in "region units". If, however, X or Y is larger than
|
||||
* 0, than first, the size of the screen is subtracted from that variable, before
|
||||
* it is then divided by the graphical size of a region. Finally, to compensate for
|
||||
* the off by one error, 1 is added at the end.
|
||||
*
|
||||
* Since only the magnitude of the distance in either direction is needed, this
|
||||
* method returns the largest absolute value of X or Y.
|
||||
*
|
||||
* The final result of this algorithm is an integer representing how far, rounded
|
||||
* up, a certain region is from the screen's edges in any direction, measured in
|
||||
* "region units". This algorithm may be flawed, in which case, I recommend simply
|
||||
* replacing it with a boolean check, to see if the region's distance from the player
|
||||
* is larger than a certain value. This algorithm lacks the advantages I initially
|
||||
* expected, so that may be beneficial at some point.
|
||||
*/
|
||||
|
||||
//locations relative to the camera
|
||||
int x = region->GetX() - camera.x;
|
||||
int y = region->GetY() - camera.y;
|
||||
|
||||
//if the region is visible, return -1
|
||||
if (x >= -REGION_WIDTH * tileSheet.GetTileW() && x < camera.width &&
|
||||
y >= -REGION_HEIGHT * tileSheet.GetTileH() && y < camera.height) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//prune the screen's area from the algorithm; get the pseudo-indexes
|
||||
if (x < 0) x /= (REGION_WIDTH * tileSheet.GetTileW());
|
||||
if (y < 0) y /= (REGION_HEIGHT * tileSheet.GetTileH());
|
||||
if (x > 0) x = (x - camera.width) / (REGION_WIDTH * tileSheet.GetTileW()) + 1;
|
||||
if (y > 0) y = (y - camera.height) / (REGION_HEIGHT * tileSheet.GetTileH()) + 1;
|
||||
|
||||
//return the pseudo-index with the greatest magnitude
|
||||
return std::max(abs(x), abs(y));
|
||||
}
|
||||
|
||||
//TODO: eew ugly
|
||||
//TODO: convert this into a more generic function?; using parameters for the bounds
|
||||
void InWorld::UpdateMap() {
|
||||
//these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1)
|
||||
int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH;
|
||||
int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH;
|
||||
|
||||
int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT;
|
||||
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
|
||||
|
||||
//prune distant regions
|
||||
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) {
|
||||
if (CheckBufferDistance(*it) > 2) {
|
||||
regionPager.UnloadRegion((*it)->GetX(), (*it)->GetY());
|
||||
//check if the region is outside off this area
|
||||
if ((*it)->GetX() < xStart || (*it)->GetX() > xEnd || (*it)->GetY() < yStart || (*it)->GetY() > yEnd) {
|
||||
|
||||
//reset
|
||||
it = regionPager.GetContainer()->begin();
|
||||
//clunky, but the alternative was time consuming
|
||||
int tmpX = (*it)->GetX();
|
||||
int tmpY = (*it)->GetY();
|
||||
++it;
|
||||
|
||||
regionPager.UnloadRegion(tmpX, tmpY);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
//TODO: make the region units official?
|
||||
int regionUnitX = REGION_WIDTH * tileSheet.GetTileW();
|
||||
int regionUnitY = REGION_HEIGHT * tileSheet.GetTileH();
|
||||
|
||||
//request empty regions, including buffers (-1 & +1 region unit)
|
||||
for (int i = snapToBase(regionUnitX, camera.x - regionUnitX); i <= snapToBase(regionUnitX, camera.x + camera.width + regionUnitX); i += regionUnitX) {
|
||||
for (int j = snapToBase(regionUnitY, camera.y - regionUnitY); j <= snapToBase(regionUnitY, camera.y + camera.height + regionUnitY); j += regionUnitY) {
|
||||
//request empty regions within this zone
|
||||
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
|
||||
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
|
||||
if (!regionPager.FindRegion(i, j)) {
|
||||
RequestRegion(i, j);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,6 @@ protected:
|
||||
void RequestRegion(int x, int y);
|
||||
|
||||
//utilities
|
||||
int CheckBufferDistance(Region* const);
|
||||
void UpdateMap();
|
||||
|
||||
//globals
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "lobby_menu.hpp"
|
||||
|
||||
#include "channels.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -91,9 +92,13 @@ void LobbyMenu::FrameEnd() {
|
||||
}
|
||||
|
||||
void LobbyMenu::Render(SDL_Surface* const screen) {
|
||||
//TODO: I need a proper UI system for the entire client and the editor
|
||||
//UI
|
||||
search.DrawTo(screen);
|
||||
join.DrawTo(screen);
|
||||
back.DrawTo(screen);
|
||||
|
||||
//TODO: draw headers for the server list
|
||||
for (int i = 0; i < serverInfo.size(); i++) {
|
||||
//draw the selected server's highlight
|
||||
if (selection == &serverInfo[i]) {
|
||||
@@ -104,6 +109,16 @@ void LobbyMenu::Render(SDL_Surface* const screen) {
|
||||
|
||||
//draw the server name
|
||||
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
|
||||
|
||||
//draw the player count
|
||||
font.DrawStringTo(to_string_custom(serverInfo[i].playerCount), screen, listBox.x + listBox.w, listBox.y + i*listBox.h);
|
||||
|
||||
//compatible?
|
||||
if (!serverInfo[i].compatible) {
|
||||
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
|
||||
}
|
||||
|
||||
//TODO: ping?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +154,8 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
||||
selection = nullptr;
|
||||
}
|
||||
|
||||
else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr) {
|
||||
else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr && selection->compatible) {
|
||||
//TODO: The player login information should be collected by the lobby screen
|
||||
//the vars
|
||||
SerialPacket packet;
|
||||
char buffer[PACKET_BUFFER_SIZE];
|
||||
@@ -184,9 +200,18 @@ void LobbyMenu::KeyUp(SDL_KeyboardEvent const& key) {
|
||||
void LobbyMenu::HandlePacket(SerialPacket packet) {
|
||||
switch(packet.meta.type) {
|
||||
case SerialPacket::Type::BROADCAST_RESPONSE: {
|
||||
//extract the data
|
||||
ServerInformation server;
|
||||
server.name = packet.serverInfo.name;
|
||||
server.address = packet.meta.srcAddress;
|
||||
server.name = packet.serverInfo.name;
|
||||
server.playerCount = packet.serverInfo.playerCount;
|
||||
|
||||
//NOTE: Check compatibility here
|
||||
server.compatible = packet.serverInfo.regionWidth == REGION_WIDTH &&
|
||||
packet.serverInfo.regionHeight == REGION_HEIGHT &&
|
||||
packet.serverInfo.regionDepth == REGION_DEPTH;
|
||||
|
||||
//push
|
||||
serverInfo.push_back(server);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -22,17 +22,24 @@
|
||||
#ifndef LOBBYMENU_HPP_
|
||||
#define LOBBYMENU_HPP_
|
||||
|
||||
#include "base_scene.hpp"
|
||||
|
||||
//graphics & utilities
|
||||
#include "image.hpp"
|
||||
#include "raster_font.hpp"
|
||||
#include "button.hpp"
|
||||
|
||||
#include "config_utility.hpp"
|
||||
|
||||
//map
|
||||
#include "region.hpp"
|
||||
|
||||
//network
|
||||
#include "udp_network_utility.hpp"
|
||||
#include "serial_packet.hpp"
|
||||
#include "serial.hpp"
|
||||
|
||||
//client
|
||||
#include "base_scene.hpp"
|
||||
|
||||
//STL
|
||||
#include <vector>
|
||||
|
||||
class LobbyMenu : public BaseScene {
|
||||
@@ -71,8 +78,11 @@ protected:
|
||||
|
||||
//server list
|
||||
struct ServerInformation {
|
||||
std::string name;
|
||||
IPaddress address;
|
||||
//TODO: version info
|
||||
std::string name;
|
||||
int playerCount;
|
||||
bool compatible;
|
||||
};
|
||||
|
||||
std::vector<ServerInformation> serverInfo;
|
||||
|
||||
@@ -53,8 +53,8 @@ void TileSheet::DrawRegionTo(SDL_Surface* const dest, Region* const region, int
|
||||
image.SetClipX((tile-1) % XCount * image.GetClipW());
|
||||
image.SetClipY((tile-1) / XCount * image.GetClipH());
|
||||
image.DrawTo(dest,
|
||||
region->GetX() + i * image.GetClipW() - camX,
|
||||
region->GetY() + j * image.GetClipH() - camY);
|
||||
(region->GetX() + i) * image.GetClipW() - camX,
|
||||
(region->GetY() + j) * image.GetClipH() - camY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
virtual Region* SaveRegion(int x, int y) = 0;
|
||||
virtual Region* CreateRegion(int x, int y) = 0;
|
||||
virtual void UnloadRegion(int x, int y) = 0;
|
||||
//TODO: delete?
|
||||
//TODO: delete existing regions
|
||||
|
||||
//accessors & mutators
|
||||
std::list<Region*>* GetContainer() { return ®ionList; }
|
||||
@@ -109,10 +109,7 @@ public:
|
||||
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) {
|
||||
if ((*it)->GetX() == x && (*it)->GetY() == y) {
|
||||
allocator.Unload(*it);
|
||||
regionList.erase(it);
|
||||
|
||||
//reset the loop, because of reasons
|
||||
it = regionList.begin();
|
||||
it = regionList.erase(it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
|
||||
@@ -36,7 +36,20 @@ void serializeType(SerialPacket* packet, char* buffer) {
|
||||
void serializeServer(SerialPacket* packet, char* buffer) {
|
||||
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||
buffer += sizeof(SerialPacket::Type);
|
||||
|
||||
//server info
|
||||
//Note: version info serialization goes here
|
||||
memcpy(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
|
||||
buffer += PACKET_STRING_SIZE;
|
||||
memcpy(buffer, &packet->serverInfo.playerCount, sizeof(int));
|
||||
buffer += sizeof(int);
|
||||
|
||||
//map format
|
||||
memcpy(buffer, &packet->serverInfo.regionWidth, sizeof(int));
|
||||
buffer += sizeof(int);
|
||||
memcpy(buffer, &packet->serverInfo.regionHeight, sizeof(int));
|
||||
buffer += sizeof(int);
|
||||
memcpy(buffer, &packet->serverInfo.regionDepth, sizeof(int));
|
||||
}
|
||||
|
||||
void serializeClient(SerialPacket* packet, char* buffer) {
|
||||
@@ -114,7 +127,20 @@ void deserializeType(SerialPacket* packet, char* buffer) {
|
||||
void deserializeServer(SerialPacket* packet, char* buffer) {
|
||||
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
|
||||
buffer += sizeof(SerialPacket::Type);
|
||||
|
||||
//server info
|
||||
//Note: version info deserialization goes here
|
||||
memcpy(packet->serverInfo.name, buffer, PACKET_STRING_SIZE);
|
||||
buffer += PACKET_STRING_SIZE;
|
||||
memcpy(&packet->serverInfo.playerCount, buffer, sizeof(int));
|
||||
buffer += sizeof(int);
|
||||
|
||||
//map format
|
||||
memcpy(&packet->serverInfo.regionWidth, buffer, sizeof(int));
|
||||
buffer += sizeof(int);
|
||||
memcpy(&packet->serverInfo.regionHeight, buffer, sizeof(int));
|
||||
buffer += sizeof(int);
|
||||
memcpy(&packet->serverInfo.regionDepth, buffer, sizeof(int));
|
||||
}
|
||||
|
||||
void deserializeClient(SerialPacket* packet, char* buffer) {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include "serial_packet.hpp"
|
||||
|
||||
/* TODO: Keep the PACKET_BUFFER_SIZE up to date
|
||||
/* NOTE: Keep the PACKET_BUFFER_SIZE up to date
|
||||
* NOTE: REGION_CONTENT is currently the largest type of packet
|
||||
* map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t)
|
||||
* map format: sizeof(int) * 2
|
||||
|
||||
@@ -79,8 +79,12 @@ union SerialPacket {
|
||||
Metadata meta;
|
||||
//TODO: version info
|
||||
char name[PACKET_STRING_SIZE];
|
||||
//TODO: player count
|
||||
//TODO: map format
|
||||
int playerCount;
|
||||
|
||||
//map format
|
||||
int regionWidth;
|
||||
int regionHeight;
|
||||
int regionDepth;
|
||||
}serverInfo;
|
||||
|
||||
//information about the client
|
||||
@@ -95,8 +99,7 @@ union SerialPacket {
|
||||
Metadata meta;
|
||||
int clientIndex;
|
||||
int playerIndex;
|
||||
//TODO: should probably move these into the client info
|
||||
//TODO: these might actually do better during the login system
|
||||
//TODO: should move handle/avatar into clientInfo; these might actually do better during the login system
|
||||
char handle[PACKET_STRING_SIZE];
|
||||
char avatar[PACKET_STRING_SIZE];
|
||||
Vector2 position;
|
||||
|
||||
@@ -110,7 +110,7 @@ void ServerApplication::Proc() {
|
||||
HandlePacket(packet);
|
||||
}
|
||||
//give the computer a break
|
||||
//TODO: remove this?
|
||||
//TODO: remove this delay?
|
||||
SDL_Delay(10);
|
||||
}
|
||||
}
|
||||
@@ -176,10 +176,16 @@ void ServerApplication::HandlePacket(SerialPacket packet) {
|
||||
void ServerApplication::HandleBroadcastRequest(SerialPacket packet) {
|
||||
//send back the server's metadata
|
||||
packet.meta.type = SerialPacket::Type::BROADCAST_RESPONSE;
|
||||
|
||||
//pack the data
|
||||
//TODO: version info
|
||||
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
|
||||
//TODO: player count
|
||||
//TODO: map format
|
||||
packet.serverInfo.playerCount = playerMap.size();
|
||||
packet.serverInfo.regionWidth = REGION_WIDTH;
|
||||
packet.serverInfo.regionHeight = REGION_HEIGHT;
|
||||
packet.serverInfo.regionDepth = REGION_DEPTH;
|
||||
|
||||
//send the data
|
||||
char buffer[PACKET_BUFFER_SIZE];
|
||||
serialize(&packet, buffer);
|
||||
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
|
||||
@@ -246,7 +252,7 @@ void ServerApplication::HandleSynchronize(SerialPacket packet) {
|
||||
SerialPacket newPacket;
|
||||
char buffer[PACKET_BUFFER_SIZE];
|
||||
|
||||
//TODO: map?
|
||||
//TODO: syncronize the map?
|
||||
|
||||
//players
|
||||
newPacket.meta.type = SerialPacket::Type::PLAYER_UPDATE;
|
||||
@@ -308,13 +314,15 @@ void ServerApplication::HandlePlayerNew(SerialPacket packet) {
|
||||
PlayerEntry::uidCounter++;
|
||||
}
|
||||
|
||||
//TODO: differentiate between delete and unload
|
||||
void ServerApplication::HandlePlayerDelete(SerialPacket packet) {
|
||||
//TODO: remove this?
|
||||
//TODO: authenticate who is deleting this player
|
||||
if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
|
||||
throw(std::runtime_error("Cannot delete a non-existant player"));
|
||||
}
|
||||
|
||||
//TODO: remove the deleted player from the database?
|
||||
|
||||
//prep the delete packet
|
||||
SerialPacket delPacket;
|
||||
delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE;
|
||||
|
||||
@@ -74,7 +74,7 @@ private:
|
||||
void HandlePlayerUpdate(SerialPacket);
|
||||
void HandleRegionRequest(SerialPacket);
|
||||
|
||||
//TODO: a function that sends to players in a certain proximity
|
||||
//TODO: a function that only sends to players in a certain proximity
|
||||
void PumpPacket(SerialPacket);
|
||||
|
||||
//APIs
|
||||
|
||||
Reference in New Issue
Block a user