Merge: New map directory structure and player passwords
commit
76e241392d
|
@ -95,6 +95,8 @@ set(minetest_SRCS
|
||||||
tile.cpp
|
tile.cpp
|
||||||
game.cpp
|
game.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
|
sha1.cpp
|
||||||
|
base64.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Server sources
|
# Server sources
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
base64.cpp and base64.h
|
||||||
|
|
||||||
|
Copyright (C) 2004-2008 René Nyffenegger
|
||||||
|
|
||||||
|
This source code is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the author be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this source code must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original source code. If you use this source code
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original source code.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "base64.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static const std::string base64_chars =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
|
"0123456789+/";
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool is_base64(unsigned char c) {
|
||||||
|
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
|
||||||
|
std::string ret;
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
unsigned char char_array_3[3];
|
||||||
|
unsigned char char_array_4[4];
|
||||||
|
|
||||||
|
while (in_len--) {
|
||||||
|
char_array_3[i++] = *(bytes_to_encode++);
|
||||||
|
if (i == 3) {
|
||||||
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||||
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||||
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||||
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||||
|
|
||||||
|
for(i = 0; (i <4) ; i++)
|
||||||
|
ret += base64_chars[char_array_4[i]];
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i)
|
||||||
|
{
|
||||||
|
for(j = i; j < 3; j++)
|
||||||
|
char_array_3[j] = '\0';
|
||||||
|
|
||||||
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||||
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||||
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||||
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||||
|
|
||||||
|
for (j = 0; (j < i + 1); j++)
|
||||||
|
ret += base64_chars[char_array_4[j]];
|
||||||
|
|
||||||
|
while((i++ < 3))
|
||||||
|
ret += '=';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string base64_decode(std::string const& encoded_string) {
|
||||||
|
int in_len = encoded_string.size();
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
int in_ = 0;
|
||||||
|
unsigned char char_array_4[4], char_array_3[3];
|
||||||
|
std::string ret;
|
||||||
|
|
||||||
|
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||||
|
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||||
|
if (i ==4) {
|
||||||
|
for (i = 0; i <4; i++)
|
||||||
|
char_array_4[i] = base64_chars.find(char_array_4[i]);
|
||||||
|
|
||||||
|
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||||
|
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||||
|
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||||
|
|
||||||
|
for (i = 0; (i < 3); i++)
|
||||||
|
ret += char_array_3[i];
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i) {
|
||||||
|
for (j = i; j <4; j++)
|
||||||
|
char_array_4[j] = 0;
|
||||||
|
|
||||||
|
for (j = 0; j <4; j++)
|
||||||
|
char_array_4[j] = base64_chars.find(char_array_4[j]);
|
||||||
|
|
||||||
|
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||||
|
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||||
|
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||||
|
|
||||||
|
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string base64_encode(unsigned char const* , unsigned int len);
|
||||||
|
std::string base64_decode(std::string const& s);
|
|
@ -68,6 +68,7 @@ void * MeshUpdateThread::Thread()
|
||||||
Client::Client(
|
Client::Client(
|
||||||
IrrlichtDevice *device,
|
IrrlichtDevice *device,
|
||||||
const char *playername,
|
const char *playername,
|
||||||
|
std::string password,
|
||||||
MapDrawControl &control):
|
MapDrawControl &control):
|
||||||
m_mesh_update_thread(),
|
m_mesh_update_thread(),
|
||||||
m_env(
|
m_env(
|
||||||
|
@ -83,7 +84,9 @@ Client::Client(
|
||||||
m_server_ser_ver(SER_FMT_VER_INVALID),
|
m_server_ser_ver(SER_FMT_VER_INVALID),
|
||||||
m_inventory_updated(false),
|
m_inventory_updated(false),
|
||||||
m_time_of_day(0),
|
m_time_of_day(0),
|
||||||
m_map_seed(0)
|
m_map_seed(0),
|
||||||
|
m_password(password),
|
||||||
|
m_access_denied(false)
|
||||||
{
|
{
|
||||||
m_packetcounter_timer = 0.0;
|
m_packetcounter_timer = 0.0;
|
||||||
m_delete_unused_sectors_timer = 0.0;
|
m_delete_unused_sectors_timer = 0.0;
|
||||||
|
@ -299,11 +302,14 @@ void Client::step(float dtime)
|
||||||
// [0] u16 TOSERVER_INIT
|
// [0] u16 TOSERVER_INIT
|
||||||
// [2] u8 SER_FMT_VER_HIGHEST
|
// [2] u8 SER_FMT_VER_HIGHEST
|
||||||
// [3] u8[20] player_name
|
// [3] u8[20] player_name
|
||||||
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE);
|
// [23] u8[28] password
|
||||||
|
SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE);
|
||||||
writeU16(&data[0], TOSERVER_INIT);
|
writeU16(&data[0], TOSERVER_INIT);
|
||||||
writeU8(&data[2], SER_FMT_VER_HIGHEST);
|
writeU8(&data[2], SER_FMT_VER_HIGHEST);
|
||||||
memset((char*)&data[3], 0, PLAYERNAME_SIZE);
|
memset((char*)&data[3], 0, PLAYERNAME_SIZE);
|
||||||
snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
|
snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
|
||||||
|
snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
|
||||||
|
|
||||||
// Send as unreliable
|
// Send as unreliable
|
||||||
Send(0, data, false);
|
Send(0, data, false);
|
||||||
}
|
}
|
||||||
|
@ -598,6 +604,15 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(command == TOCLIENT_ACCESS_DENIED)
|
||||||
|
{
|
||||||
|
// The server didn't like our password. Note, this needs
|
||||||
|
// to be processed even if the serialisation format has
|
||||||
|
// not been agreed yet, the same as TOCLIENT_INIT.
|
||||||
|
m_access_denied = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(ser_version == SER_FMT_VER_INVALID)
|
if(ser_version == SER_FMT_VER_INVALID)
|
||||||
{
|
{
|
||||||
dout_client<<DTIME<<"WARNING: Client: Server serialization"
|
dout_client<<DTIME<<"WARNING: Client: Server serialization"
|
||||||
|
|
|
@ -207,6 +207,7 @@ public:
|
||||||
Client(
|
Client(
|
||||||
IrrlichtDevice *device,
|
IrrlichtDevice *device,
|
||||||
const char *playername,
|
const char *playername,
|
||||||
|
std::string password,
|
||||||
MapDrawControl &control
|
MapDrawControl &control
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -377,6 +378,11 @@ public:
|
||||||
// Get event from queue. CE_NONE is returned if queue is empty.
|
// Get event from queue. CE_NONE is returned if queue is empty.
|
||||||
ClientEvent getClientEvent();
|
ClientEvent getClientEvent();
|
||||||
|
|
||||||
|
inline bool accessDenied()
|
||||||
|
{
|
||||||
|
return m_access_denied;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Virtual methods from con::PeerHandler
|
// Virtual methods from con::PeerHandler
|
||||||
|
@ -430,6 +436,9 @@ private:
|
||||||
// The seed returned by the server in TOCLIENT_INIT is stored here
|
// The seed returned by the server in TOCLIENT_INIT is stored here
|
||||||
u64 m_map_seed;
|
u64 m_map_seed;
|
||||||
|
|
||||||
|
std::string m_password;
|
||||||
|
bool m_access_denied;
|
||||||
|
|
||||||
InventoryContext m_inventory_context;
|
InventoryContext m_inventory_context;
|
||||||
|
|
||||||
Queue<ClientEvent> m_client_event_queue;
|
Queue<ClientEvent> m_client_event_queue;
|
||||||
|
|
|
@ -150,6 +150,11 @@ enum ToClientCommand
|
||||||
f1000 player pitch
|
f1000 player pitch
|
||||||
f1000 player yaw
|
f1000 player yaw
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
TOCLIENT_ACCESS_DENIED = 0x35,
|
||||||
|
/*
|
||||||
|
u16 command
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ToServerCommand
|
enum ToServerCommand
|
||||||
|
@ -161,6 +166,7 @@ enum ToServerCommand
|
||||||
[0] u16 TOSERVER_INIT
|
[0] u16 TOSERVER_INIT
|
||||||
[2] u8 SER_FMT_VER_HIGHEST
|
[2] u8 SER_FMT_VER_HIGHEST
|
||||||
[3] u8[20] player_name
|
[3] u8[20] player_name
|
||||||
|
[23] u8[28] password
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TOSERVER_INIT2 = 0x11,
|
TOSERVER_INIT2 = 0x11,
|
||||||
|
|
|
@ -290,5 +290,24 @@ bool RecursiveDeleteContent(std::string path)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CreateAllDirs(std::string path)
|
||||||
|
{
|
||||||
|
|
||||||
|
size_t pos;
|
||||||
|
std::vector<std::string> tocreate;
|
||||||
|
std::string basepath = path;
|
||||||
|
while(!PathExists(basepath))
|
||||||
|
{
|
||||||
|
tocreate.push_back(basepath);
|
||||||
|
pos = basepath.rfind('/');
|
||||||
|
if(pos == std::string::npos)
|
||||||
|
return false;
|
||||||
|
basepath = basepath.substr(0,pos);
|
||||||
|
}
|
||||||
|
for(int i=tocreate.size()-1;i>=0;i--)
|
||||||
|
CreateDir(tocreate[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ std::vector<DirListNode> GetDirListing(std::string path);
|
||||||
// Returns true if already exists
|
// Returns true if already exists
|
||||||
bool CreateDir(std::string path);
|
bool CreateDir(std::string path);
|
||||||
|
|
||||||
|
// Create all directories on the given path that don't already exist.
|
||||||
|
bool CreateAllDirs(std::string path);
|
||||||
|
|
||||||
bool PathExists(std::string path);
|
bool PathExists(std::string path);
|
||||||
|
|
||||||
// Only pass full paths to this one. True on success.
|
// Only pass full paths to this one. True on success.
|
||||||
|
|
22
src/game.cpp
22
src/game.cpp
|
@ -634,6 +634,7 @@ void the_game(
|
||||||
gui::IGUIFont* font,
|
gui::IGUIFont* font,
|
||||||
std::string map_dir,
|
std::string map_dir,
|
||||||
std::string playername,
|
std::string playername,
|
||||||
|
std::string password,
|
||||||
std::string address,
|
std::string address,
|
||||||
u16 port,
|
u16 port,
|
||||||
std::wstring &error_message
|
std::wstring &error_message
|
||||||
|
@ -672,7 +673,6 @@ void the_game(
|
||||||
guienv->drawAll();
|
guienv->drawAll();
|
||||||
driver->endScene();
|
driver->endScene();
|
||||||
|
|
||||||
std::cout<<DTIME<<"Creating server and client"<<std::endl;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create server.
|
Create server.
|
||||||
|
@ -680,6 +680,7 @@ void the_game(
|
||||||
*/
|
*/
|
||||||
SharedPtr<Server> server;
|
SharedPtr<Server> server;
|
||||||
if(address == ""){
|
if(address == ""){
|
||||||
|
std::cout<<DTIME<<"Creating server"<<std::endl;
|
||||||
server = new Server(map_dir);
|
server = new Server(map_dir);
|
||||||
server->start(port);
|
server->start(port);
|
||||||
}
|
}
|
||||||
|
@ -688,7 +689,8 @@ void the_game(
|
||||||
Create client
|
Create client
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Client client(device, playername.c_str(), draw_control);
|
std::cout<<DTIME<<"Creating client"<<std::endl;
|
||||||
|
Client client(device, playername.c_str(), password, draw_control);
|
||||||
|
|
||||||
Address connect_address(0,0,0,0, port);
|
Address connect_address(0,0,0,0, port);
|
||||||
try{
|
try{
|
||||||
|
@ -727,6 +729,10 @@ void the_game(
|
||||||
could_connect = true;
|
could_connect = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(client.accessDenied())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Wait for 10 seconds
|
// Wait for 10 seconds
|
||||||
if(time_counter >= 10.0)
|
if(time_counter >= 10.0)
|
||||||
{
|
{
|
||||||
|
@ -755,8 +761,16 @@ void the_game(
|
||||||
|
|
||||||
if(could_connect == false)
|
if(could_connect == false)
|
||||||
{
|
{
|
||||||
std::cout<<DTIME<<"Timed out."<<std::endl;
|
if(client.accessDenied())
|
||||||
error_message = L"Connection timed out.";
|
{
|
||||||
|
error_message = L"Access denied. Check your password and try again.";
|
||||||
|
std::cout<<DTIME<<"Access denied."<<std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error_message = L"Connection timed out.";
|
||||||
|
std::cout<<DTIME<<"Timed out."<<std::endl;
|
||||||
|
}
|
||||||
gui_loadingtext->remove();
|
gui_loadingtext->remove();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ void the_game(
|
||||||
gui::IGUIFont* font,
|
gui::IGUIFont* font,
|
||||||
std::string map_dir,
|
std::string map_dir,
|
||||||
std::string playername,
|
std::string playername,
|
||||||
|
std::string password,
|
||||||
std::string address,
|
std::string address,
|
||||||
u16 port,
|
u16 port,
|
||||||
std::wstring &error_message
|
std::wstring &error_message
|
||||||
|
|
|
@ -164,30 +164,38 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nickname
|
// Nickname + password
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 100, 20);
|
core::rect<s32> rect(0, 0, 110, 20);
|
||||||
rect += topleft_client + v2s32(40, 50+6);
|
rect += topleft_client + v2s32(35, 50+6);
|
||||||
const wchar_t *text = L"Nickname";
|
const wchar_t *text = L"Name/Password";
|
||||||
Environment->addStaticText(text, rect, false, true, this, -1);
|
Environment->addStaticText(text, rect, false, true, this, -1);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 250, 30);
|
core::rect<s32> rect(0, 0, 230, 30);
|
||||||
rect += topleft_client + v2s32(160, 50);
|
rect += topleft_client + v2s32(160, 50);
|
||||||
gui::IGUIElement *e =
|
gui::IGUIElement *e =
|
||||||
Environment->addEditBox(text_name.c_str(), rect, true, this, 258);
|
Environment->addEditBox(text_name.c_str(), rect, true, this, 258);
|
||||||
if(text_name == L"")
|
if(text_name == L"")
|
||||||
Environment->setFocus(e);
|
Environment->setFocus(e);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
core::rect<s32> rect(0, 0, 120, 30);
|
||||||
|
rect += topleft_client + v2s32(size_client.X-60-100, 50);
|
||||||
|
gui::IGUIEditBox *e =
|
||||||
|
Environment->addEditBox(L"", rect, true, this, 264);
|
||||||
|
e->setPasswordBox(true);
|
||||||
|
|
||||||
|
}
|
||||||
// Address + port
|
// Address + port
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 100, 20);
|
core::rect<s32> rect(0, 0, 110, 20);
|
||||||
rect += topleft_client + v2s32(40, 100+6);
|
rect += topleft_client + v2s32(35, 100+6);
|
||||||
const wchar_t *text = L"Address + Port";
|
const wchar_t *text = L"Address/Port";
|
||||||
Environment->addStaticText(text, rect, false, true, this, -1);
|
Environment->addStaticText(text, rect, false, true, this, -1);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 250, 30);
|
core::rect<s32> rect(0, 0, 230, 30);
|
||||||
rect += topleft_client + v2s32(160, 100);
|
rect += topleft_client + v2s32(160, 100);
|
||||||
gui::IGUIElement *e =
|
gui::IGUIElement *e =
|
||||||
Environment->addEditBox(text_address.c_str(), rect, true, this, 256);
|
Environment->addEditBox(text_address.c_str(), rect, true, this, 256);
|
||||||
|
@ -195,9 +203,9 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
||||||
Environment->setFocus(e);
|
Environment->setFocus(e);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 100, 30);
|
core::rect<s32> rect(0, 0, 120, 30);
|
||||||
//rect += topleft_client + v2s32(160+250+20, 125);
|
//rect += topleft_client + v2s32(160+250+20, 125);
|
||||||
rect += topleft_client + v2s32(size_client.X-40-100, 100);
|
rect += topleft_client + v2s32(size_client.X-60-100, 100);
|
||||||
Environment->addEditBox(text_port.c_str(), rect, true, this, 257);
|
Environment->addEditBox(text_port.c_str(), rect, true, this, 257);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@ -208,13 +216,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 250, 30);
|
core::rect<s32> rect(0, 0, 250, 30);
|
||||||
rect += topleft_client + v2s32(40, 150);
|
rect += topleft_client + v2s32(35, 150);
|
||||||
Environment->addCheckBox(fancy_trees, rect, this, 263,
|
Environment->addCheckBox(fancy_trees, rect, this, 263,
|
||||||
L"Fancy trees");
|
L"Fancy trees");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 250, 30);
|
core::rect<s32> rect(0, 0, 250, 30);
|
||||||
rect += topleft_client + v2s32(40, 150+30);
|
rect += topleft_client + v2s32(35, 150+30);
|
||||||
Environment->addCheckBox(smooth_lighting, rect, this, 262,
|
Environment->addCheckBox(smooth_lighting, rect, this, 262,
|
||||||
L"Smooth Lighting");
|
L"Smooth Lighting");
|
||||||
}
|
}
|
||||||
|
@ -245,12 +253,12 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
||||||
// Server parameters
|
// Server parameters
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 250, 30);
|
core::rect<s32> rect(0, 0, 250, 30);
|
||||||
rect += topleft_server + v2s32(40, 30);
|
rect += topleft_server + v2s32(35, 30);
|
||||||
Environment->addCheckBox(creative_mode, rect, this, 259, L"Creative Mode");
|
Environment->addCheckBox(creative_mode, rect, this, 259, L"Creative Mode");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 250, 30);
|
core::rect<s32> rect(0, 0, 250, 30);
|
||||||
rect += topleft_server + v2s32(40, 60);
|
rect += topleft_server + v2s32(35, 60);
|
||||||
Environment->addCheckBox(enable_damage, rect, this, 261, L"Enable Damage");
|
Environment->addCheckBox(enable_damage, rect, this, 261, L"Enable Damage");
|
||||||
}
|
}
|
||||||
// Map delete button
|
// Map delete button
|
||||||
|
@ -296,6 +304,11 @@ void GUIMainMenu::acceptInput()
|
||||||
if(e != NULL)
|
if(e != NULL)
|
||||||
m_data->name = e->getText();
|
m_data->name = e->getText();
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
gui::IGUIElement *e = getElementFromId(264);
|
||||||
|
if(e != NULL)
|
||||||
|
m_data->password = e->getText();
|
||||||
|
}
|
||||||
{
|
{
|
||||||
gui::IGUIElement *e = getElementFromId(256);
|
gui::IGUIElement *e = getElementFromId(256);
|
||||||
if(e != NULL)
|
if(e != NULL)
|
||||||
|
@ -380,7 +393,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
|
||||||
{
|
{
|
||||||
switch(event.GUIEvent.Caller->getID())
|
switch(event.GUIEvent.Caller->getID())
|
||||||
{
|
{
|
||||||
case 256: case 257: case 258:
|
case 256: case 257: case 258: case 264:
|
||||||
acceptInput();
|
acceptInput();
|
||||||
quitMenu();
|
quitMenu();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -46,6 +46,7 @@ struct MainMenuData
|
||||||
std::wstring address;
|
std::wstring address;
|
||||||
std::wstring port;
|
std::wstring port;
|
||||||
std::wstring name;
|
std::wstring name;
|
||||||
|
std::wstring password;
|
||||||
bool fancy_trees;
|
bool fancy_trees;
|
||||||
bool smooth_lighting;
|
bool smooth_lighting;
|
||||||
// Server options
|
// Server options
|
||||||
|
|
28
src/main.cpp
28
src/main.cpp
|
@ -325,6 +325,8 @@ Making it more portable:
|
||||||
#include "materials.h"
|
#include "materials.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "keycode.h"
|
#include "keycode.h"
|
||||||
|
#include "sha1.h"
|
||||||
|
#include "base64.h"
|
||||||
|
|
||||||
// This makes textures
|
// This makes textures
|
||||||
ITextureSource *g_texturesource = NULL;
|
ITextureSource *g_texturesource = NULL;
|
||||||
|
@ -1170,6 +1172,7 @@ int main(int argc, char *argv[])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
More parameters
|
More parameters
|
||||||
*/
|
*/
|
||||||
|
@ -1324,11 +1327,15 @@ int main(int argc, char *argv[])
|
||||||
*/
|
*/
|
||||||
std::wstring error_message = L"";
|
std::wstring error_message = L"";
|
||||||
|
|
||||||
|
// The password entered during the menu screen,
|
||||||
|
std::string password;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Menu-game loop
|
Menu-game loop
|
||||||
*/
|
*/
|
||||||
while(device->run() && kill == false)
|
while(device->run() && kill == false)
|
||||||
{
|
{
|
||||||
|
|
||||||
// This is used for catching disconnects
|
// This is used for catching disconnects
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1428,6 +1435,26 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
playername = wide_to_narrow(menudata.name);
|
playername = wide_to_narrow(menudata.name);
|
||||||
|
|
||||||
|
// Get an sha-1 hash of the player's name combined with
|
||||||
|
// the password entered. That's what the server uses as
|
||||||
|
// their password. (Exception : if the password field is
|
||||||
|
// blank, we send a blank password - this is for backwards
|
||||||
|
// compatibility with password-less players).
|
||||||
|
if(menudata.password.length() > 0)
|
||||||
|
{
|
||||||
|
std::string slt=playername + wide_to_narrow(menudata.password);
|
||||||
|
SHA1 *sha1 = new SHA1();
|
||||||
|
sha1->addBytes(slt.c_str(), slt.length());
|
||||||
|
unsigned char *digest = sha1->getDigest();
|
||||||
|
password = base64_encode(digest, 20);
|
||||||
|
free(digest);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
password = "";
|
||||||
|
}
|
||||||
|
|
||||||
address = wide_to_narrow(menudata.address);
|
address = wide_to_narrow(menudata.address);
|
||||||
int newport = stoi(wide_to_narrow(menudata.port));
|
int newport = stoi(wide_to_narrow(menudata.port));
|
||||||
if(newport != 0)
|
if(newport != 0)
|
||||||
|
@ -1474,6 +1501,7 @@ int main(int argc, char *argv[])
|
||||||
font,
|
font,
|
||||||
map_dir,
|
map_dir,
|
||||||
playername,
|
playername,
|
||||||
|
password,
|
||||||
address,
|
address,
|
||||||
port,
|
port,
|
||||||
error_message
|
error_message
|
||||||
|
|
122
src/map.cpp
122
src/map.cpp
|
@ -4875,9 +4875,9 @@ plan_b:
|
||||||
return (s16)level;
|
return (s16)level;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerMap::createDir(std::string path)
|
void ServerMap::createDirs(std::string path)
|
||||||
{
|
{
|
||||||
if(fs::CreateDir(path) == false)
|
if(fs::CreateAllDirs(path) == false)
|
||||||
{
|
{
|
||||||
m_dout<<DTIME<<"ServerMap: Failed to create directory "
|
m_dout<<DTIME<<"ServerMap: Failed to create directory "
|
||||||
<<"\""<<path<<"\""<<std::endl;
|
<<"\""<<path<<"\""<<std::endl;
|
||||||
|
@ -4885,29 +4885,52 @@ void ServerMap::createDir(std::string path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServerMap::getSectorSubDir(v2s16 pos)
|
std::string ServerMap::getSectorDir(v2s16 pos, int layout)
|
||||||
{
|
{
|
||||||
char cc[9];
|
char cc[9];
|
||||||
snprintf(cc, 9, "%.4x%.4x",
|
switch(layout)
|
||||||
(unsigned int)pos.X&0xffff,
|
{
|
||||||
(unsigned int)pos.Y&0xffff);
|
case 1:
|
||||||
|
snprintf(cc, 9, "%.4x%.4x",
|
||||||
|
(unsigned int)pos.X&0xffff,
|
||||||
|
(unsigned int)pos.Y&0xffff);
|
||||||
|
|
||||||
return std::string(cc);
|
return m_savedir + "/sectors/" + cc;
|
||||||
}
|
case 2:
|
||||||
|
snprintf(cc, 9, "%.3x/%.3x",
|
||||||
|
(unsigned int)pos.X&0xfff,
|
||||||
|
(unsigned int)pos.Y&0xfff);
|
||||||
|
|
||||||
std::string ServerMap::getSectorDir(v2s16 pos)
|
return m_savedir + "/sectors2/" + cc;
|
||||||
{
|
default:
|
||||||
return m_savedir + "/sectors/" + getSectorSubDir(pos);
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v2s16 ServerMap::getSectorPos(std::string dirname)
|
v2s16 ServerMap::getSectorPos(std::string dirname)
|
||||||
{
|
{
|
||||||
if(dirname.size() != 8)
|
|
||||||
throw InvalidFilenameException("Invalid sector directory name");
|
|
||||||
unsigned int x, y;
|
unsigned int x, y;
|
||||||
int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
|
int r;
|
||||||
if(r != 2)
|
size_t spos = dirname.rfind('/') + 1;
|
||||||
throw InvalidFilenameException("Invalid sector directory name");
|
assert(spos != std::string::npos);
|
||||||
|
if(dirname.size() - spos == 8)
|
||||||
|
{
|
||||||
|
// Old layout
|
||||||
|
r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
|
||||||
|
}
|
||||||
|
else if(dirname.size() - spos == 3)
|
||||||
|
{
|
||||||
|
// New layout
|
||||||
|
r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
|
||||||
|
// Sign-extend the 12 bit values up to 16 bits...
|
||||||
|
if(x&0x800) x|=0xF000;
|
||||||
|
if(y&0x800) y|=0xF000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
assert(r == 2);
|
||||||
v2s16 pos((s16)x, (s16)y);
|
v2s16 pos((s16)x, (s16)y);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -5106,7 +5129,7 @@ void ServerMap::saveMapMeta()
|
||||||
<<"seed="<<m_seed<<", chunksize="<<m_chunksize
|
<<"seed="<<m_seed<<", chunksize="<<m_chunksize
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
|
|
||||||
createDir(m_savedir);
|
createDirs(m_savedir);
|
||||||
|
|
||||||
std::string fullpath = m_savedir + "/map_meta.txt";
|
std::string fullpath = m_savedir + "/map_meta.txt";
|
||||||
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
||||||
|
@ -5179,7 +5202,7 @@ void ServerMap::saveChunkMeta()
|
||||||
dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
|
dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
|
||||||
<<count<<" chunks"<<std::endl;
|
<<count<<" chunks"<<std::endl;
|
||||||
|
|
||||||
createDir(m_savedir);
|
createDirs(m_savedir);
|
||||||
|
|
||||||
std::string fullpath = m_savedir + "/chunk_meta";
|
std::string fullpath = m_savedir + "/chunk_meta";
|
||||||
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
||||||
|
@ -5267,10 +5290,8 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
|
||||||
u8 version = SER_FMT_VER_HIGHEST;
|
u8 version = SER_FMT_VER_HIGHEST;
|
||||||
// Get destination
|
// Get destination
|
||||||
v2s16 pos = sector->getPos();
|
v2s16 pos = sector->getPos();
|
||||||
createDir(m_savedir);
|
|
||||||
createDir(m_savedir+"/sectors");
|
|
||||||
std::string dir = getSectorDir(pos);
|
std::string dir = getSectorDir(pos);
|
||||||
createDir(dir);
|
createDirs(dir);
|
||||||
|
|
||||||
std::string fullpath = dir + "/meta";
|
std::string fullpath = dir + "/meta";
|
||||||
std::ofstream o(fullpath.c_str(), std::ios_base::binary);
|
std::ofstream o(fullpath.c_str(), std::ios_base::binary);
|
||||||
|
@ -5282,22 +5303,21 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
|
||||||
sector->differs_from_disk = false;
|
sector->differs_from_disk = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapSector* ServerMap::loadSectorMeta(std::string dirname)
|
MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
// Get destination
|
// Get destination
|
||||||
v2s16 p2d = getSectorPos(dirname);
|
v2s16 p2d = getSectorPos(sectordir);
|
||||||
std::string dir = m_savedir + "/sectors/" + dirname;
|
|
||||||
|
|
||||||
ServerMapSector *sector = NULL;
|
ServerMapSector *sector = NULL;
|
||||||
|
|
||||||
std::string fullpath = dir + "/meta";
|
std::string fullpath = sectordir + "/meta";
|
||||||
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
||||||
if(is.good() == false)
|
if(is.good() == false)
|
||||||
{
|
{
|
||||||
// If the directory exists anyway, it probably is in some old
|
// If the directory exists anyway, it probably is in some old
|
||||||
// format. Just go ahead and create the sector.
|
// format. Just go ahead and create the sector.
|
||||||
if(fs::PathExists(dir))
|
if(fs::PathExists(sectordir))
|
||||||
{
|
{
|
||||||
dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
|
dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
|
||||||
<<fullpath<<" doesn't exist but directory does."
|
<<fullpath<<" doesn't exist but directory does."
|
||||||
|
@ -5307,12 +5327,16 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
|
||||||
m_sectors.insert(p2d, sector);
|
m_sectors.insert(p2d, sector);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
throw FileNotGoodException("Cannot open sector metafile");
|
throw FileNotGoodException("Cannot open sector metafile");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sector = ServerMapSector::deSerialize
|
sector = ServerMapSector::deSerialize
|
||||||
(is, this, p2d, m_sectors);
|
(is, this, p2d, m_sectors);
|
||||||
|
if(save_after_load)
|
||||||
|
saveSectorMeta(sector);
|
||||||
}
|
}
|
||||||
|
|
||||||
sector->differs_from_disk = false;
|
sector->differs_from_disk = false;
|
||||||
|
@ -5323,14 +5347,31 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
|
||||||
bool ServerMap::loadSectorFull(v2s16 p2d)
|
bool ServerMap::loadSectorFull(v2s16 p2d)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
std::string sectorsubdir = getSectorSubDir(p2d);
|
|
||||||
|
|
||||||
MapSector *sector = NULL;
|
MapSector *sector = NULL;
|
||||||
|
|
||||||
|
// The directory layout we're going to load from.
|
||||||
|
// 1 - original sectors/xxxxzzzz/
|
||||||
|
// 2 - new sectors2/xxx/zzz/
|
||||||
|
// If we load from anything but the latest structure, we will
|
||||||
|
// immediately save to the new one, and remove the old.
|
||||||
|
int loadlayout = 1;
|
||||||
|
std::string sectordir1 = getSectorDir(p2d, 1);
|
||||||
|
std::string sectordir;
|
||||||
|
if(fs::PathExists(sectordir1))
|
||||||
|
{
|
||||||
|
sectordir = sectordir1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loadlayout = 2;
|
||||||
|
sectordir = getSectorDir(p2d, 2);
|
||||||
|
}
|
||||||
|
|
||||||
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
||||||
|
|
||||||
try{
|
try{
|
||||||
sector = loadSectorMeta(sectorsubdir);
|
sector = loadSectorMeta(sectordir, loadlayout != 2);
|
||||||
}
|
}
|
||||||
catch(InvalidFilenameException &e)
|
catch(InvalidFilenameException &e)
|
||||||
{
|
{
|
||||||
|
@ -5349,7 +5390,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
|
||||||
Load blocks
|
Load blocks
|
||||||
*/
|
*/
|
||||||
std::vector<fs::DirListNode> list2 = fs::GetDirListing
|
std::vector<fs::DirListNode> list2 = fs::GetDirListing
|
||||||
(m_savedir+"/sectors/"+sectorsubdir);
|
(sectordir);
|
||||||
std::vector<fs::DirListNode>::iterator i2;
|
std::vector<fs::DirListNode>::iterator i2;
|
||||||
for(i2=list2.begin(); i2!=list2.end(); i2++)
|
for(i2=list2.begin(); i2!=list2.end(); i2++)
|
||||||
{
|
{
|
||||||
|
@ -5357,16 +5398,25 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
|
||||||
if(i2->dir)
|
if(i2->dir)
|
||||||
continue;
|
continue;
|
||||||
try{
|
try{
|
||||||
loadBlock(sectorsubdir, i2->name, sector);
|
loadBlock(sectordir, i2->name, sector, loadlayout != 2);
|
||||||
}
|
}
|
||||||
catch(InvalidFilenameException &e)
|
catch(InvalidFilenameException &e)
|
||||||
{
|
{
|
||||||
// This catches unknown crap in directory
|
// This catches unknown crap in directory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(loadlayout != 2)
|
||||||
|
{
|
||||||
|
dstream<<"Sector converted to new layout - deleting "<<
|
||||||
|
sectordir1<<std::endl;
|
||||||
|
fs::RecursiveDelete(sectordir1);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ServerMap::saveBlock(MapBlock *block)
|
void ServerMap::saveBlock(MapBlock *block)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
@ -5386,12 +5436,9 @@ void ServerMap::saveBlock(MapBlock *block)
|
||||||
// Get destination
|
// Get destination
|
||||||
v3s16 p3d = block->getPos();
|
v3s16 p3d = block->getPos();
|
||||||
v2s16 p2d(p3d.X, p3d.Z);
|
v2s16 p2d(p3d.X, p3d.Z);
|
||||||
createDir(m_savedir);
|
|
||||||
createDir(m_savedir+"/sectors");
|
|
||||||
std::string dir = getSectorDir(p2d);
|
std::string dir = getSectorDir(p2d);
|
||||||
createDir(dir);
|
createDirs(dir);
|
||||||
|
|
||||||
// Block file is map/sectors/xxxxxxxx/xxxx
|
|
||||||
char cc[5];
|
char cc[5];
|
||||||
snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
|
snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
|
||||||
std::string fullpath = dir + "/" + cc;
|
std::string fullpath = dir + "/" + cc;
|
||||||
|
@ -5427,12 +5474,11 @@ void ServerMap::saveBlock(MapBlock *block)
|
||||||
block->resetChangedFlag();
|
block->resetChangedFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
|
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
|
||||||
// Block file is map/sectors/xxxxxxxx/xxxx
|
std::string fullpath = sectordir+"/"+blockfile;
|
||||||
std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
|
|
||||||
try{
|
try{
|
||||||
|
|
||||||
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
||||||
|
@ -5496,7 +5542,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Save old format blocks in new format
|
// Save old format blocks in new format
|
||||||
if(version < SER_FMT_VER_HIGHEST)
|
if(version < SER_FMT_VER_HIGHEST || save_after_load)
|
||||||
{
|
{
|
||||||
saveBlock(block);
|
saveBlock(block);
|
||||||
}
|
}
|
||||||
|
|
12
src/map.h
12
src/map.h
|
@ -545,13 +545,9 @@ public:
|
||||||
Misc. helper functions for fiddling with directory and file
|
Misc. helper functions for fiddling with directory and file
|
||||||
names when saving
|
names when saving
|
||||||
*/
|
*/
|
||||||
void createDir(std::string path);
|
void createDirs(std::string path);
|
||||||
void createSaveDir();
|
|
||||||
// returns something like "xxxxxxxx"
|
|
||||||
std::string getSectorSubDir(v2s16 pos);
|
|
||||||
// returns something like "map/sectors/xxxxxxxx"
|
// returns something like "map/sectors/xxxxxxxx"
|
||||||
std::string getSectorDir(v2s16 pos);
|
std::string getSectorDir(v2s16 pos, int layout = 2);
|
||||||
std::string createSectorDir(v2s16 pos);
|
|
||||||
// dirname: final directory name
|
// dirname: final directory name
|
||||||
v2s16 getSectorPos(std::string dirname);
|
v2s16 getSectorPos(std::string dirname);
|
||||||
v3s16 getBlockPos(std::string sectordir, std::string blockfile);
|
v3s16 getBlockPos(std::string sectordir, std::string blockfile);
|
||||||
|
@ -572,7 +568,7 @@ public:
|
||||||
// (no MapBlocks)
|
// (no MapBlocks)
|
||||||
// DEPRECATED? Sectors have no metadata anymore.
|
// DEPRECATED? Sectors have no metadata anymore.
|
||||||
void saveSectorMeta(ServerMapSector *sector);
|
void saveSectorMeta(ServerMapSector *sector);
|
||||||
MapSector* loadSectorMeta(std::string dirname);
|
MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
|
||||||
|
|
||||||
// Full load of a sector including all blocks.
|
// Full load of a sector including all blocks.
|
||||||
// returns true on success, false on failure.
|
// returns true on success, false on failure.
|
||||||
|
@ -583,7 +579,7 @@ public:
|
||||||
|
|
||||||
void saveBlock(MapBlock *block);
|
void saveBlock(MapBlock *block);
|
||||||
// This will generate a sector with getSector if not found.
|
// This will generate a sector with getSector if not found.
|
||||||
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
|
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
|
||||||
|
|
||||||
// For debug printing
|
// For debug printing
|
||||||
virtual void PrintInfo(std::ostream &out);
|
virtual void PrintInfo(std::ostream &out);
|
||||||
|
|
|
@ -87,6 +87,7 @@ Player::Player():
|
||||||
m_position(0,0,0)
|
m_position(0,0,0)
|
||||||
{
|
{
|
||||||
updateName("<not set>");
|
updateName("<not set>");
|
||||||
|
updatePassword("");
|
||||||
resetInventory();
|
resetInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +146,7 @@ void Player::serialize(std::ostream &os)
|
||||||
Settings args;
|
Settings args;
|
||||||
args.setS32("version", 1);
|
args.setS32("version", 1);
|
||||||
args.set("name", m_name);
|
args.set("name", m_name);
|
||||||
|
args.set("password", m_password);
|
||||||
args.setFloat("pitch", m_pitch);
|
args.setFloat("pitch", m_pitch);
|
||||||
args.setFloat("yaw", m_yaw);
|
args.setFloat("yaw", m_yaw);
|
||||||
args.setV3F("position", m_position);
|
args.setV3F("position", m_position);
|
||||||
|
@ -179,6 +181,10 @@ void Player::deSerialize(std::istream &is)
|
||||||
//args.getS32("version");
|
//args.getS32("version");
|
||||||
std::string name = args.get("name");
|
std::string name = args.get("name");
|
||||||
updateName(name.c_str());
|
updateName(name.c_str());
|
||||||
|
std::string password = "";
|
||||||
|
if(args.exists("password"))
|
||||||
|
password = args.get("password");
|
||||||
|
updatePassword(password.c_str());
|
||||||
m_pitch = args.getFloat("pitch");
|
m_pitch = args.getFloat("pitch");
|
||||||
m_yaw = args.getFloat("yaw");
|
m_yaw = args.getFloat("yaw");
|
||||||
m_position = args.getV3F("position");
|
m_position = args.getV3F("position");
|
||||||
|
|
13
src/player.h
13
src/player.h
|
@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "collision.h"
|
#include "collision.h"
|
||||||
|
|
||||||
#define PLAYERNAME_SIZE 20
|
#define PLAYERNAME_SIZE 20
|
||||||
|
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
|
||||||
|
// base64-encoded SHA-1.
|
||||||
|
|
||||||
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
|
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
|
||||||
|
|
||||||
|
@ -121,6 +123,16 @@ public:
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void updatePassword(const char *password)
|
||||||
|
{
|
||||||
|
snprintf(m_password, PASSWORD_SIZE, "%s", password);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * getPassword()
|
||||||
|
{
|
||||||
|
return m_password;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool isLocal() const = 0;
|
virtual bool isLocal() const = 0;
|
||||||
|
|
||||||
virtual void updateLight(u8 light_at_pos) {};
|
virtual void updateLight(u8 light_at_pos) {};
|
||||||
|
@ -157,6 +169,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
char m_name[PLAYERNAME_SIZE];
|
char m_name[PLAYERNAME_SIZE];
|
||||||
|
char m_password[PASSWORD_SIZE];
|
||||||
f32 m_pitch;
|
f32 m_pitch;
|
||||||
f32 m_yaw;
|
f32 m_yaw;
|
||||||
v3f m_speed;
|
v3f m_speed;
|
||||||
|
|
|
@ -1734,8 +1734,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
// [0] u16 TOSERVER_INIT
|
// [0] u16 TOSERVER_INIT
|
||||||
// [2] u8 SER_FMT_VER_HIGHEST
|
// [2] u8 SER_FMT_VER_HIGHEST
|
||||||
// [3] u8[20] player_name
|
// [3] u8[20] player_name
|
||||||
|
// [23] u8[28] password <--- can be sent without this, from old versions
|
||||||
|
|
||||||
if(datasize < 3)
|
if(datasize < 2+1+PLAYERNAME_SIZE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
|
derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
|
||||||
|
@ -1767,17 +1768,41 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Get player name
|
// Get player name
|
||||||
const u32 playername_size = 20;
|
char playername[PLAYERNAME_SIZE];
|
||||||
char playername[playername_size];
|
for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
|
||||||
for(u32 i=0; i<playername_size-1; i++)
|
|
||||||
{
|
{
|
||||||
playername[i] = data[3+i];
|
playername[i] = data[3+i];
|
||||||
}
|
}
|
||||||
playername[playername_size-1] = 0;
|
playername[PLAYERNAME_SIZE-1] = 0;
|
||||||
|
|
||||||
|
// Get password
|
||||||
|
char password[PASSWORD_SIZE];
|
||||||
|
if(datasize == 2+1+PLAYERNAME_SIZE)
|
||||||
|
{
|
||||||
|
// old version - assume blank password
|
||||||
|
password[0] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(u32 i=0; i<PASSWORD_SIZE-1; i++)
|
||||||
|
{
|
||||||
|
password[i] = data[23+i];
|
||||||
|
}
|
||||||
|
password[PASSWORD_SIZE-1] = 0;
|
||||||
|
}
|
||||||
|
Player *checkplayer = m_env.getPlayer(playername);
|
||||||
|
if(checkplayer != NULL && strcmp(checkplayer->getPassword(),password))
|
||||||
|
{
|
||||||
|
derr_server<<DTIME<<"Server: peer_id="<<peer_id
|
||||||
|
<<": supplied invalid password for "
|
||||||
|
<<playername<<std::endl;
|
||||||
|
SendAccessDenied(m_con, peer_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get player
|
// Get player
|
||||||
Player *player = emergePlayer(playername, "", peer_id);
|
Player *player = emergePlayer(playername, password, peer_id);
|
||||||
//Player *player = m_env.getPlayer(peer_id);
|
|
||||||
|
|
||||||
/*{
|
/*{
|
||||||
// DEBUG: Test serialization
|
// DEBUG: Test serialization
|
||||||
|
@ -3138,6 +3163,20 @@ void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
|
||||||
con.Send(peer_id, 0, data, true);
|
con.Send(peer_id, 0, data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Server::SendAccessDenied(con::Connection &con, u16 peer_id)
|
||||||
|
{
|
||||||
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
std::ostringstream os(std::ios_base::binary);
|
||||||
|
|
||||||
|
writeU16(os, TOCLIENT_ACCESS_DENIED);
|
||||||
|
|
||||||
|
// Make data buffer
|
||||||
|
std::string s = os.str();
|
||||||
|
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||||
|
// Send as reliable
|
||||||
|
con.Send(peer_id, 0, data, true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Non-static send methods
|
Non-static send methods
|
||||||
*/
|
*/
|
||||||
|
@ -4052,8 +4091,7 @@ v3f findSpawnPos(ServerMap &map)
|
||||||
), BS);
|
), BS);
|
||||||
}
|
}
|
||||||
|
|
||||||
Player *Server::emergePlayer(const char *name, const char *password,
|
Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
|
||||||
u16 peer_id)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Try to get an existing player
|
Try to get an existing player
|
||||||
|
@ -4099,6 +4137,7 @@ Player *Server::emergePlayer(const char *name, const char *password,
|
||||||
//player->peer_id = PEER_ID_INEXISTENT;
|
//player->peer_id = PEER_ID_INEXISTENT;
|
||||||
player->peer_id = peer_id;
|
player->peer_id = peer_id;
|
||||||
player->updateName(name);
|
player->updateName(name);
|
||||||
|
player->updatePassword(password);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set player position
|
Set player position
|
||||||
|
|
|
@ -436,6 +436,7 @@ private:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
|
static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
|
||||||
|
static void SendAccessDenied(con::Connection &con, u16 peer_id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Non-static send methods
|
Non-static send methods
|
||||||
|
@ -476,11 +477,12 @@ private:
|
||||||
/*
|
/*
|
||||||
Get a player from memory or creates one.
|
Get a player from memory or creates one.
|
||||||
If player is already connected, return NULL
|
If player is already connected, return NULL
|
||||||
|
The password is not checked here - it is only used to
|
||||||
|
set the password if a new player is created.
|
||||||
|
|
||||||
Call with env and con locked.
|
Call with env and con locked.
|
||||||
*/
|
*/
|
||||||
Player *emergePlayer(const char *name, const char *password,
|
Player *emergePlayer(const char *name, const char *password, u16 peer_id);
|
||||||
u16 peer_id);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update water pressure.
|
Update water pressure.
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
/* sha1.cpp
|
||||||
|
|
||||||
|
Copyright (c) 2005 Michael D. Leonhard
|
||||||
|
|
||||||
|
http://tamale.net/
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "sha1.h"
|
||||||
|
|
||||||
|
// print out memory in hexadecimal
|
||||||
|
void SHA1::hexPrinter( unsigned char* c, int l )
|
||||||
|
{
|
||||||
|
assert( c );
|
||||||
|
assert( l > 0 );
|
||||||
|
while( l > 0 )
|
||||||
|
{
|
||||||
|
printf( " %02x", *c );
|
||||||
|
l--;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// circular left bit rotation. MSB wraps around to LSB
|
||||||
|
Uint32 SHA1::lrot( Uint32 x, int bits )
|
||||||
|
{
|
||||||
|
return (x<<bits) | (x>>(32 - bits));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Save a 32-bit unsigned integer to memory, in big-endian order
|
||||||
|
void SHA1::storeBigEndianUint32( unsigned char* byte, Uint32 num )
|
||||||
|
{
|
||||||
|
assert( byte );
|
||||||
|
byte[0] = (unsigned char)(num>>24);
|
||||||
|
byte[1] = (unsigned char)(num>>16);
|
||||||
|
byte[2] = (unsigned char)(num>>8);
|
||||||
|
byte[3] = (unsigned char)num;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor *******************************************************
|
||||||
|
SHA1::SHA1()
|
||||||
|
{
|
||||||
|
// make sure that the data type is the right size
|
||||||
|
assert( sizeof( Uint32 ) * 5 == 20 );
|
||||||
|
|
||||||
|
// initialize
|
||||||
|
H0 = 0x67452301;
|
||||||
|
H1 = 0xefcdab89;
|
||||||
|
H2 = 0x98badcfe;
|
||||||
|
H3 = 0x10325476;
|
||||||
|
H4 = 0xc3d2e1f0;
|
||||||
|
unprocessedBytes = 0;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor ********************************************************
|
||||||
|
SHA1::~SHA1()
|
||||||
|
{
|
||||||
|
// erase data
|
||||||
|
H0 = H1 = H2 = H3 = H4 = 0;
|
||||||
|
for( int c = 0; c < 64; c++ ) bytes[c] = 0;
|
||||||
|
unprocessedBytes = size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process ***********************************************************
|
||||||
|
void SHA1::process()
|
||||||
|
{
|
||||||
|
assert( unprocessedBytes == 64 );
|
||||||
|
//printf( "process: " ); hexPrinter( bytes, 64 ); printf( "\n" );
|
||||||
|
int t;
|
||||||
|
Uint32 a, b, c, d, e, K, f, W[80];
|
||||||
|
// starting values
|
||||||
|
a = H0;
|
||||||
|
b = H1;
|
||||||
|
c = H2;
|
||||||
|
d = H3;
|
||||||
|
e = H4;
|
||||||
|
// copy and expand the message block
|
||||||
|
for( t = 0; t < 16; t++ ) W[t] = (bytes[t*4] << 24)
|
||||||
|
+(bytes[t*4 + 1] << 16)
|
||||||
|
+(bytes[t*4 + 2] << 8)
|
||||||
|
+ bytes[t*4 + 3];
|
||||||
|
for(; t< 80; t++ ) W[t] = lrot( W[t-3]^W[t-8]^W[t-14]^W[t-16], 1 );
|
||||||
|
|
||||||
|
/* main loop */
|
||||||
|
Uint32 temp;
|
||||||
|
for( t = 0; t < 80; t++ )
|
||||||
|
{
|
||||||
|
if( t < 20 ) {
|
||||||
|
K = 0x5a827999;
|
||||||
|
f = (b & c) | ((b ^ 0xFFFFFFFF) & d);//TODO: try using ~
|
||||||
|
} else if( t < 40 ) {
|
||||||
|
K = 0x6ed9eba1;
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
} else if( t < 60 ) {
|
||||||
|
K = 0x8f1bbcdc;
|
||||||
|
f = (b & c) | (b & d) | (c & d);
|
||||||
|
} else {
|
||||||
|
K = 0xca62c1d6;
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
}
|
||||||
|
temp = lrot(a,5) + f + e + W[t] + K;
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = lrot(b,30);
|
||||||
|
b = a;
|
||||||
|
a = temp;
|
||||||
|
//printf( "t=%d %08x %08x %08x %08x %08x\n",t,a,b,c,d,e );
|
||||||
|
}
|
||||||
|
/* add variables */
|
||||||
|
H0 += a;
|
||||||
|
H1 += b;
|
||||||
|
H2 += c;
|
||||||
|
H3 += d;
|
||||||
|
H4 += e;
|
||||||
|
//printf( "Current: %08x %08x %08x %08x %08x\n",H0,H1,H2,H3,H4 );
|
||||||
|
/* all bytes have been processed */
|
||||||
|
unprocessedBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// addBytes **********************************************************
|
||||||
|
void SHA1::addBytes( const char* data, int num )
|
||||||
|
{
|
||||||
|
assert( data );
|
||||||
|
assert( num > 0 );
|
||||||
|
// add these bytes to the running total
|
||||||
|
size += num;
|
||||||
|
// repeat until all data is processed
|
||||||
|
while( num > 0 )
|
||||||
|
{
|
||||||
|
// number of bytes required to complete block
|
||||||
|
int needed = 64 - unprocessedBytes;
|
||||||
|
assert( needed > 0 );
|
||||||
|
// number of bytes to copy (use smaller of two)
|
||||||
|
int toCopy = (num < needed) ? num : needed;
|
||||||
|
// Copy the bytes
|
||||||
|
memcpy( bytes + unprocessedBytes, data, toCopy );
|
||||||
|
// Bytes have been copied
|
||||||
|
num -= toCopy;
|
||||||
|
data += toCopy;
|
||||||
|
unprocessedBytes += toCopy;
|
||||||
|
|
||||||
|
// there is a full block
|
||||||
|
if( unprocessedBytes == 64 ) process();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// digest ************************************************************
|
||||||
|
unsigned char* SHA1::getDigest()
|
||||||
|
{
|
||||||
|
// save the message size
|
||||||
|
Uint32 totalBitsL = size << 3;
|
||||||
|
Uint32 totalBitsH = size >> 29;
|
||||||
|
// add 0x80 to the message
|
||||||
|
addBytes( "\x80", 1 );
|
||||||
|
|
||||||
|
unsigned char footer[64] = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
// block has no room for 8-byte filesize, so finish it
|
||||||
|
if( unprocessedBytes > 56 )
|
||||||
|
addBytes( (char*)footer, 64 - unprocessedBytes);
|
||||||
|
assert( unprocessedBytes <= 56 );
|
||||||
|
// how many zeros do we need
|
||||||
|
int neededZeros = 56 - unprocessedBytes;
|
||||||
|
// store file size (in bits) in big-endian format
|
||||||
|
storeBigEndianUint32( footer + neededZeros , totalBitsH );
|
||||||
|
storeBigEndianUint32( footer + neededZeros + 4, totalBitsL );
|
||||||
|
// finish the final block
|
||||||
|
addBytes( (char*)footer, neededZeros + 8 );
|
||||||
|
// allocate memory for the digest bytes
|
||||||
|
unsigned char* digest = (unsigned char*)malloc( 20 );
|
||||||
|
// copy the digest bytes
|
||||||
|
storeBigEndianUint32( digest, H0 );
|
||||||
|
storeBigEndianUint32( digest + 4, H1 );
|
||||||
|
storeBigEndianUint32( digest + 8, H2 );
|
||||||
|
storeBigEndianUint32( digest + 12, H3 );
|
||||||
|
storeBigEndianUint32( digest + 16, H4 );
|
||||||
|
// return the digest
|
||||||
|
return digest;
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* sha1.h
|
||||||
|
|
||||||
|
Copyright (c) 2005 Michael D. Leonhard
|
||||||
|
|
||||||
|
http://tamale.net/
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHA1_HEADER
|
||||||
|
typedef unsigned int Uint32;
|
||||||
|
|
||||||
|
class SHA1
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// fields
|
||||||
|
Uint32 H0, H1, H2, H3, H4;
|
||||||
|
unsigned char bytes[64];
|
||||||
|
int unprocessedBytes;
|
||||||
|
Uint32 size;
|
||||||
|
void process();
|
||||||
|
public:
|
||||||
|
SHA1();
|
||||||
|
~SHA1();
|
||||||
|
void addBytes( const char* data, int num );
|
||||||
|
unsigned char* getDigest();
|
||||||
|
// utility methods
|
||||||
|
static Uint32 lrot( Uint32 x, int bits );
|
||||||
|
static void storeBigEndianUint32( unsigned char* byte, Uint32 num );
|
||||||
|
static void hexPrinter( unsigned char* c, int l );
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SHA1_HEADER
|
||||||
|
#endif
|
Loading…
Reference in New Issue