Merge pull request #5194 from IntelOrca/refactor/more-istream

Use IStream instead of SDL in more places
This commit is contained in:
Ted John 2017-02-09 17:56:55 +00:00 committed by GitHub
commit c4e89278c1
23 changed files with 408 additions and 431 deletions

View File

@ -21,6 +21,7 @@
#include "../core/Guard.hpp"
#include "../core/Path.hpp"
#include "../ParkImporter.h"
#include "../rct2/S6Exporter.h"
#include "CommandLine.hpp"
extern "C"
@ -102,74 +103,56 @@ exitcode_t CommandLine::HandleCommandConvert(CommandLineArgEnumerator * enumerat
WriteConvertFromAndToMessage(sourceFileType, destinationFileType);
gOpenRCT2Headless = true;
if (!openrct2_initialise()) {
if (!openrct2_initialise())
{
Console::Error::WriteLine("Error while initialising OpenRCT2.");
return EXITCODE_FAIL;
}
if (sourceFileType == FILE_EXTENSION_SV4 ||
sourceFileType == FILE_EXTENSION_SC4)
try
{
try
{
auto s4Importer = std::unique_ptr<IParkImporter>(ParkImporter::CreateS4());
if (sourceFileType == FILE_EXTENSION_SC4)
{
s4Importer->LoadScenario(sourcePath);
}
if (sourceFileType == FILE_EXTENSION_SV4)
{
s4Importer->LoadSavedGame(sourcePath);
}
s4Importer->Import();
if (sourceFileType == FILE_EXTENSION_SC4)
{
// We are converting a scenario, so reset the park
scenario_begin();
}
}
catch (const Exception &ex)
{
Console::Error::WriteLine(ex.GetMessage());
return EXITCODE_FAIL;
}
auto importer = std::unique_ptr<IParkImporter>(ParkImporter::Create(sourcePath));
importer->Load(sourcePath);
importer->Import();
}
else
catch (const Exception &ex)
{
if (sourceFileType == FILE_EXTENSION_SC6)
{
scenario_load_and_play_from_path(sourcePath);
}
if (sourceFileType == FILE_EXTENSION_SV6)
{
game_load_save(sourcePath);
}
Console::Error::WriteLine(ex.GetMessage());
return EXITCODE_FAIL;
}
SDL_RWops* rw = SDL_RWFromFile(destinationPath, "wb+");
if (rw != NULL) {
if (sourceFileType == FILE_EXTENSION_SC4 ||
sourceFileType == FILE_EXTENSION_SC6)
{
// We are converting a scenario, so reset the park
scenario_begin();
}
try
{
auto exporter = std::make_unique<S6Exporter>();
// HACK remove the main window so it saves the park with the
// correct initial view
window_close_by_class(WC_MAIN_WINDOW);
exporter->Export();
if (destinationFileType == FILE_EXTENSION_SC6)
{
scenario_save(rw, 0x80000002);
exporter->SaveScenario(destinationPath);
}
else
{
scenario_save(rw, 0x80000001);
exporter->SaveGame(destinationPath);
}
SDL_RWclose(rw);
Console::WriteLine("Conversion successful!");
}
else
catch (const Exception &ex)
{
Console::Error::WriteLine("Unable to write destination file.");
Console::Error::WriteLine(ex.GetMessage());
return EXITCODE_FAIL;
}
Console::WriteLine("Conversion successful!");
return EXITCODE_OK;
}

View File

@ -25,7 +25,8 @@
enum
{
FILE_MODE_OPEN,
FILE_MODE_WRITE
FILE_MODE_WRITE,
FILE_MODE_APPEND,
};
/**
@ -61,6 +62,11 @@ public:
_canRead = true;
_canWrite = true;
break;
case FILE_MODE_APPEND:
mode = "a";
_canRead = false;
_canWrite = true;
break;
default:
throw;
}

View File

@ -63,7 +63,12 @@ MemoryStream::~MemoryStream()
_data = nullptr;
}
void * MemoryStream::GetData() const
const void * MemoryStream::GetData() const
{
return _data;
}
void * MemoryStream::GetDataCopy() const
{
return Memory::Duplicate(_data, _dataSize);
}
@ -173,7 +178,9 @@ void MemoryStream::EnsureCapacity(size_t capacity)
newCapacity *= 2;
}
uint64 position = GetPosition();
_dataCapacity = newCapacity;
Memory::Reallocate(_data, _dataCapacity);
_data = Memory::Reallocate(_data, _dataCapacity);
_position = (void *)((uintptr_t)_data + (uintptr_t)position);
}
}

View File

@ -46,7 +46,8 @@ public:
MemoryStream(const void * data, size_t dataSize);
virtual ~MemoryStream();
void * GetData() const;
const void * GetData() const;
void * GetDataCopy() const;
void * TakeData();
///////////////////////////////////////////////////////////////////////////

View File

@ -168,7 +168,6 @@ sint32 game_do_command_p(sint32 command, sint32 *eax, sint32 *ebx, sint32 *ecx,
void game_load_or_quit_no_save_prompt();
bool game_load_sv6_path(const char * path);
bool game_load_sv6(SDL_RWops* rw);
sint32 game_load_network(SDL_RWops* rw);
bool game_load_save(const utf8 *path);
void game_load_init();
void game_pause_toggle(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp);

View File

@ -16,13 +16,14 @@
#ifndef DISABLE_NETWORK
#include "NetworkKey.h"
#include "../diagnostic.h"
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <vector>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include "../core/IStream.hpp"
#include "../diagnostic.h"
#include "NetworkKey.h"
#define KEY_TYPE EVP_PKEY_RSA
@ -90,10 +91,11 @@ bool NetworkKey::Generate()
return true;
}
bool NetworkKey::LoadPrivate(SDL_RWops * file)
bool NetworkKey::LoadPrivate(IStream * stream)
{
assert(file != nullptr);
size_t size = (size_t)file->size(file);
Guard::ArgumentNotNull(stream);
size_t size = (size_t)stream->GetLength();
if (size == (size_t)-1)
{
log_error("unknown size, refusing to load key");
@ -105,7 +107,7 @@ bool NetworkKey::LoadPrivate(SDL_RWops * file)
return false;
}
char * priv_key = new char[size];
file->read(file, priv_key, 1, size);
stream->Read(priv_key, size);
BIO * bio = BIO_new_mem_buf(priv_key, (sint32)size);
if (bio == nullptr)
{
@ -134,10 +136,11 @@ bool NetworkKey::LoadPrivate(SDL_RWops * file)
return true;
}
bool NetworkKey::LoadPublic(SDL_RWops * file)
bool NetworkKey::LoadPublic(IStream * stream)
{
assert(file != nullptr);
size_t size = (size_t)file->size(file);
Guard::ArgumentNotNull(stream);
size_t size = (size_t)stream->GetLength();
if (size == (size_t)-1)
{
log_error("unknown size, refusing to load key");
@ -149,7 +152,7 @@ bool NetworkKey::LoadPublic(SDL_RWops * file)
return false;
}
char * pub_key = new char[size];
file->read(file, pub_key, 1, size);
stream->Read(pub_key, size);
BIO * bio = BIO_new_mem_buf(pub_key, (sint32)size);
if (bio == nullptr)
{
@ -171,7 +174,7 @@ bool NetworkKey::LoadPublic(SDL_RWops * file)
return true;
}
bool NetworkKey::SavePrivate(SDL_RWops *file)
bool NetworkKey::SavePrivate(IStream * stream)
{
if (_key == nullptr)
{
@ -208,7 +211,7 @@ bool NetworkKey::SavePrivate(SDL_RWops *file)
sint32 keylen = BIO_pending(bio);
char * pem_key = new char[keylen];
BIO_read(bio, pem_key, keylen);
file->write(file, pem_key, keylen, 1);
stream->Write(pem_key, keylen);
log_verbose("saving key of length %u", keylen);
BIO_free_all(bio);
delete [] pem_key;
@ -219,7 +222,7 @@ bool NetworkKey::SavePrivate(SDL_RWops *file)
return true;
}
bool NetworkKey::SavePublic(SDL_RWops *file)
bool NetworkKey::SavePublic(IStream * stream)
{
if (_key == nullptr)
{
@ -250,7 +253,7 @@ bool NetworkKey::SavePublic(SDL_RWops *file)
sint32 keylen = BIO_pending(bio);
char * pem_key = new char[keylen];
BIO_read(bio, pem_key, keylen);
file->write(file, pem_key, keylen, 1);
stream->Write(pem_key, keylen);
BIO_free_all(bio);
delete [] pem_key;

View File

@ -21,22 +21,23 @@
#include "../common.h"
#include <SDL_rwops.h>
#include <string>
typedef struct evp_pkey_st EVP_PKEY;
typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
interface IStream;
class NetworkKey final
{
public:
NetworkKey();
~NetworkKey();
bool Generate();
bool LoadPrivate(SDL_RWops * file);
bool LoadPublic(SDL_RWops * file);
bool SavePrivate(SDL_RWops * file);
bool SavePublic(SDL_RWops * file);
bool LoadPrivate(IStream * stream);
bool LoadPublic(IStream * stream);
bool SavePrivate(IStream * stream);
bool SavePublic(IStream * stream);
std::string PublicKeyString();
std::string PublicKeyHash();
void Unload();

View File

@ -66,6 +66,10 @@
constexpr uint32 CONNECT_TIMEOUT_MS = 3000;
#ifdef __WINDOWS__
static bool _wsaInitialised = false;
#endif
class TcpSocket;
class SocketException : public Exception
@ -431,7 +435,7 @@ private:
explicit TcpSocket(SOCKET socket)
{
_socket = socket;
_status = SOCKET_STATUS_CONNECTED;
_status = SOCKET_STATUS_CONNECTED;
}
void CloseSocket()
@ -492,4 +496,48 @@ ITcpSocket * CreateTcpSocket()
return new TcpSocket();
}
bool InitialiseWSA()
{
#ifdef __WINDOWS__
if (!_wsaInitialised)
{
log_verbose("Initialising WSA");
WSADATA wsa_data;
if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0)
{
log_error("Unable to initialise winsock.");
return false;
}
_wsaInitialised = true;
}
return _wsaInitialised;
#else
return true;
#endif
}
void DisposeWSA()
{
#ifdef __WINDOWS__
if (_wsaInitialised)
{
WSACleanup();
_wsaInitialised = false;
}
#endif
}
namespace Convert
{
uint16 HostToNetwork(uint16 value)
{
return htons(value);
}
uint16 NetworkToHost(uint16 value)
{
return ntohs(value);
}
}
#endif

View File

@ -62,3 +62,12 @@ public:
};
ITcpSocket * CreateTcpSocket();
bool InitialiseWSA();
void DisposeWSA();
namespace Convert
{
uint16 HostToNetwork(uint16 value);
uint16 NetworkToHost(uint16 value);
}

View File

@ -16,19 +16,12 @@
#include <SDL_platform.h>
#ifdef __WINDOWS__
// winsock2 must be included before windows.h
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#include "../core/Guard.hpp"
#include "../OpenRCT2.h"
extern "C" {
#include "../OpenRCT2.h"
#include "../platform/platform.h"
#include "../util/sawyercoding.h"
#include "../platform/platform.h"
#include "../util/sawyercoding.h"
}
#include "network.h"
@ -45,13 +38,16 @@ sint32 _pickup_peep_old_x = SPRITE_LOCATION_NULL;
#include <string>
#include "../core/Console.hpp"
#include "../core/FileStream.hpp"
#include "../core/Json.hpp"
#include "../core/Math.hpp"
#include "../core/MemoryStream.h"
#include "../core/Path.hpp"
#include "../core/String.hpp"
#include "../core/Util.hpp"
#include "../object/ObjectManager.h"
#include "../object/ObjectRepository.h"
#include "../ParkImporter.h"
#include "../rct2/S6Exporter.h"
extern "C" {
@ -130,17 +126,9 @@ Network::~Network()
bool Network::Init()
{
#ifdef __WINDOWS__
if (!wsa_initialized) {
log_verbose("Initialising WSA");
WSADATA wsa_data;
if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) {
log_error("Unable to initialise winsock.");
return false;
}
wsa_initialized = true;
if (!InitialiseWSA()) {
return false;
}
#endif
status = NETWORK_STATUS_READY;
@ -183,12 +171,7 @@ void Network::Close()
player_list.clear();
group_list.clear();
#ifdef __WINDOWS__
if (wsa_initialized) {
WSACleanup();
wsa_initialized = false;
}
#endif
DisposeWSA();
CloseChatLog();
gfx_invalidate_screen();
@ -229,36 +212,47 @@ bool Network::BeginClient(const char* host, uint16 port)
return false;
}
SDL_RWops *privkey = SDL_RWFromFile(keyPath, "wb+");
if (privkey == nullptr) {
try
{
auto fs = FileStream(keyPath, FILE_MODE_WRITE);
_key.SavePrivate(&fs);
}
catch (Exception)
{
log_error("Unable to save private key at %s.", keyPath);
return false;
}
_key.SavePrivate(privkey);
SDL_RWclose(privkey);
const std::string hash = _key.PublicKeyHash();
const utf8 *publicKeyHash = hash.c_str();
network_get_public_key_path(keyPath, sizeof(keyPath), gConfigNetwork.player_name, publicKeyHash);
Console::WriteLine("Key generated, saving public bits as %s", keyPath);
SDL_RWops *pubkey = SDL_RWFromFile(keyPath, "wb+");
if (pubkey == nullptr) {
try
{
auto fs = FileStream(keyPath, FILE_MODE_WRITE);
_key.SavePublic(&fs);
}
catch (Exception)
{
log_error("Unable to save public key at %s.", keyPath);
return false;
}
_key.SavePublic(pubkey);
SDL_RWclose(pubkey);
} else {
log_verbose("Loading key from %s", keyPath);
SDL_RWops *privkey = SDL_RWFromFile(keyPath, "rb");
if (privkey == nullptr) {
// LoadPrivate returns validity of loaded key
bool ok = false;
try
{
log_verbose("Loading key from %s", keyPath);
auto fs = FileStream(keyPath, FILE_MODE_OPEN);
ok = _key.LoadPrivate(&fs);
}
catch (Exception)
{
log_error("Unable to read private key from %s.", keyPath);
return false;
}
// LoadPrivate returns validity of loaded key
bool ok = _key.LoadPrivate(privkey);
SDL_RWclose(privkey);
// Don't store private key in memory when it's not in use.
_key.Unload();
return ok;
@ -813,10 +807,11 @@ void Network::AppendChatLog(const utf8 *text)
utf8 directory[MAX_PATH];
Path::GetDirectory(directory, sizeof(directory), chatLogPath);
if (platform_ensure_directory_exists(directory)) {
_chatLogStream = SDL_RWFromFile(chatLogPath, "a");
if (_chatLogStream != nullptr) {
utf8 buffer[256];
try
{
_chatLogStream = new FileStream(chatLogPath, FILE_MODE_APPEND);
utf8 buffer[256];
time_t timer;
struct tm * tmInfo;
time(&timer);
@ -827,8 +822,12 @@ void Network::AppendChatLog(const utf8 *text)
utf8_remove_formatting(buffer, false);
String::Append(buffer, sizeof(buffer), PLATFORM_NEWLINE);
SDL_RWwrite(_chatLogStream, buffer, strlen(buffer), 1);
SDL_RWclose(_chatLogStream);
_chatLogStream->Write(buffer, strlen(buffer));
delete _chatLogStream;
_chatLogStream = nullptr;
}
catch (const Exception &)
{
}
}
}
@ -916,14 +915,6 @@ void Network::Server_Send_AUTH(NetworkConnection& connection)
void Network::Server_Send_MAP(NetworkConnection* connection)
{
FILE* temp = tmpfile();
if (!temp) {
log_warning("Failed to create temporary file to save map.");
return;
}
SDL_RWops* rw = SDL_RWFromFP(temp, SDL_TRUE);
size_t out_size;
uint8 *header;
std::vector<const ObjectRepositoryItem *> objects;
if (connection) {
objects = connection->RequestedObjects;
@ -933,8 +924,9 @@ void Network::Server_Send_MAP(NetworkConnection* connection)
IObjectManager * objManager = GetObjectManager();
objects = objManager->GetPackableObjects();
}
header = save_for_network(rw, out_size, objects);
SDL_RWclose(rw);
size_t out_size;
uint8 * header = save_for_network(out_size, objects);
if (header == nullptr) {
if (connection) {
connection->SetLastDisconnectReason(STR_MULTIPLAYER_CONNECTION_CLOSED);
@ -957,22 +949,24 @@ void Network::Server_Send_MAP(NetworkConnection* connection)
free(header);
}
uint8 * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size, const std::vector<const ObjectRepositoryItem *> &objects) const
uint8 * Network::save_for_network(size_t &out_size, const std::vector<const ObjectRepositoryItem *> &objects) const
{
uint8 * header = nullptr;
out_size = 0;
bool RLEState = gUseRLE;
gUseRLE = false;
scenario_save_network(rw_buffer, objects);
gUseRLE = RLEState;
sint32 size = (sint32)SDL_RWtell(rw_buffer);
std::vector<uint8> buffer(size);
SDL_RWseek(rw_buffer, 0, RW_SEEK_SET);
if (SDL_RWread(rw_buffer, &buffer[0], size, 1) == 0) {
log_warning("Failed to read temporary map file into memory.");
auto ms = MemoryStream();
if (!SaveMap(&ms, objects)) {
log_warning("Failed to export map.");
return nullptr;
}
uint8 *compressed = util_zlib_deflate(&buffer[0], size, &out_size);
gUseRLE = RLEState;
const void * data = ms.GetData();
sint32 size = ms.GetLength();
uint8 *compressed = util_zlib_deflate((const uint8 *)data, size, &out_size);
if (compressed != NULL)
{
header = (uint8 *)_strdup("open2_sv6_zlib");
@ -993,7 +987,7 @@ uint8 * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size, const
log_error("Failed to allocate %u bytes.", size);
} else {
out_size = size;
memcpy(header, &buffer[0], size);
memcpy(header, data, size);
}
}
return header;
@ -1381,15 +1375,23 @@ void Network::Client_Handle_TOKEN(NetworkConnection& connection, NetworkPacket&
log_error("Key file (%s) was not found. Restart client to re-generate it.", keyPath);
return;
}
SDL_RWops *privkey = SDL_RWFromFile(keyPath, "rb");
bool ok = _key.LoadPrivate(privkey);
SDL_RWclose(privkey);
if (!ok) {
try
{
auto fs = FileStream(keyPath, FILE_MODE_OPEN);
if (!_key.LoadPrivate(&fs))
{
throw Exception();
}
}
catch (Exception)
{
log_error("Failed to load key %s", keyPath);
connection.SetLastDisconnectReason(STR_MULTIPLAYER_VERIFICATION_FAILURE);
connection.Socket->Disconnect();
return;
}
uint32 challenge_size;
packet >> challenge_size;
const char *challenge = (const char *)packet.Read(challenge_size);
@ -1398,7 +1400,7 @@ void Network::Client_Handle_TOKEN(NetworkConnection& connection, NetworkPacket&
const std::string pubkey = _key.PublicKeyString();
_challenge.resize(challenge_size);
memcpy(_challenge.data(), challenge, challenge_size);
ok = _key.Sign(_challenge.data(), _challenge.size(), &signature, &sigsize);
bool ok = _key.Sign(_challenge.data(), _challenge.size(), &signature, &sigsize);
if (!ok) {
log_error("Failed to sign server's challenge.");
connection.SetLastDisconnectReason(STR_MULTIPLAYER_VERIFICATION_FAILURE);
@ -1552,26 +1554,45 @@ void Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& p
if (pubkey == nullptr) {
connection.AuthStatus = NETWORK_AUTH_VERIFICATIONFAILURE;
} else {
const char *signature = (const char *)packet.Read(sigsize);
SDL_RWops *pubkey_rw = SDL_RWFromConstMem(pubkey, (sint32)strlen(pubkey));
if (signature == nullptr || pubkey_rw == nullptr) {
connection.AuthStatus = NETWORK_AUTH_VERIFICATIONFAILURE;
log_verbose("Signature verification failed, invalid data!");
} else {
connection.Key.LoadPublic(pubkey_rw);
SDL_RWclose(pubkey_rw);
try
{
const char *signature = (const char *)packet.Read(sigsize);
if (signature == nullptr)
{
throw Exception();
}
auto ms = MemoryStream(pubkey, strlen(pubkey));
if (!connection.Key.LoadPublic(&ms))
{
throw Exception();
}
bool verified = connection.Key.Verify(connection.Challenge.data(), connection.Challenge.size(), signature, sigsize);
const std::string hash = connection.Key.PublicKeyHash();
if (verified) {
connection.AuthStatus = NETWORK_AUTH_VERIFIED;
if (verified)
{
log_verbose("Signature verification ok. Hash %s", hash.c_str());
} else {
if (gConfigNetwork.known_keys_only && _userManager.GetUserByHash(hash) == nullptr)
{
log_verbose("Hash %s, not known", hash.c_str());
connection.AuthStatus = NETWORK_AUTH_UNKNOWN_KEY_DISALLOWED;
}
else
{
connection.AuthStatus = NETWORK_AUTH_VERIFIED;
}
}
else
{
connection.AuthStatus = NETWORK_AUTH_VERIFICATIONFAILURE;
log_verbose("Signature verification failed!");
}
if (gConfigNetwork.known_keys_only && _userManager.GetUserByHash(hash) == nullptr) {
connection.AuthStatus = NETWORK_AUTH_UNKNOWN_KEY_DISALLOWED;
}
}
catch (Exception)
{
connection.AuthStatus = NETWORK_AUTH_VERIFICATIONFAILURE;
log_verbose("Signature verification failed, invalid data!");
}
}
@ -1649,8 +1670,10 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa
} else {
log_verbose("Assuming received map is in plain sv6 format");
}
SDL_RWops* rw = SDL_RWFromMem(data, (sint32)data_size);
if (game_load_network(rw)) {
auto ms = MemoryStream(data, data_size);
if (LoadMap(&ms))
{
game_load_init();
game_command_queue.clear();
server_tick = gCurrentTicks;
@ -1667,7 +1690,6 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa
//Something went wrong, game is not loaded. Return to main screen.
game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0);
}
SDL_RWclose(rw);
if (has_to_free)
{
free(data);
@ -1675,6 +1697,99 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa
}
}
bool Network::LoadMap(IStream * stream)
{
bool result = false;
try
{
auto importer = std::unique_ptr<IParkImporter>(ParkImporter::CreateS6());
importer->LoadFromStream(stream, false);
importer->Import();
sprite_position_tween_reset();
// Read checksum
uint32 checksum = stream->ReadValue<uint32>();
UNUSED(checksum);
// Read other data not in normal save files
stream->Read(gSpriteSpatialIndex, 0x10001 * sizeof(uint16));
gGamePaused = stream->ReadValue<uint32>();
_guestGenerationProbability = stream->ReadValue<uint32>();
_suggestedGuestMaximum = stream->ReadValue<uint32>();
gCheatsSandboxMode = stream->ReadValue<uint8>() != 0;
gCheatsDisableClearanceChecks = stream->ReadValue<uint8>() != 0;
gCheatsDisableSupportLimits = stream->ReadValue<uint8>() != 0;
gCheatsDisableTrainLengthLimit = stream->ReadValue<uint8>() != 0;
gCheatsEnableChainLiftOnAllTrack = stream->ReadValue<uint8>() != 0;
gCheatsShowAllOperatingModes = stream->ReadValue<uint8>() != 0;
gCheatsShowVehiclesFromOtherTrackTypes = stream->ReadValue<uint8>() != 0;
gCheatsFastLiftHill = stream->ReadValue<uint8>() != 0;
gCheatsDisableBrakesFailure = stream->ReadValue<uint8>() != 0;
gCheatsDisableAllBreakdowns = stream->ReadValue<uint8>() != 0;
gCheatsUnlockAllPrices = stream->ReadValue<uint8>() != 0;
gCheatsBuildInPauseMode = stream->ReadValue<uint8>() != 0;
gCheatsIgnoreRideIntensity = stream->ReadValue<uint8>() != 0;
gCheatsDisableVandalism = stream->ReadValue<uint8>() != 0;
gCheatsDisableLittering = stream->ReadValue<uint8>() != 0;
gCheatsNeverendingMarketing = stream->ReadValue<uint8>() != 0;
gCheatsFreezeClimate = stream->ReadValue<uint8>() != 0;
gCheatsDisablePlantAging = stream->ReadValue<uint8>() != 0;
gCheatsAllowArbitraryRideTypeChanges = stream->ReadValue<uint8>() != 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
result = true;
}
catch (const Exception &)
{
}
return result;
}
bool Network::SaveMap(IStream * stream, const std::vector<const ObjectRepositoryItem *> &objects) const
{
bool result = false;
viewport_set_saved_view();
try
{
auto s6exporter = std::make_unique<S6Exporter>();
s6exporter->ExportObjectsList = objects;
s6exporter->Export();
s6exporter->SaveGame(stream);
// Write other data not in normal save files
stream->Write(gSpriteSpatialIndex, 0x10001 * sizeof(uint16));
stream->WriteValue<uint32>(gGamePaused);
stream->WriteValue<uint32>(_guestGenerationProbability);
stream->WriteValue<uint32>(_suggestedGuestMaximum);
stream->WriteValue<uint8>(gCheatsSandboxMode);
stream->WriteValue<uint8>(gCheatsDisableClearanceChecks);
stream->WriteValue<uint8>(gCheatsDisableSupportLimits);
stream->WriteValue<uint8>(gCheatsDisableTrainLengthLimit);
stream->WriteValue<uint8>(gCheatsEnableChainLiftOnAllTrack);
stream->WriteValue<uint8>(gCheatsShowAllOperatingModes);
stream->WriteValue<uint8>(gCheatsShowVehiclesFromOtherTrackTypes);
stream->WriteValue<uint8>(gCheatsFastLiftHill);
stream->WriteValue<uint8>(gCheatsDisableBrakesFailure);
stream->WriteValue<uint8>(gCheatsDisableAllBreakdowns);
stream->WriteValue<uint8>(gCheatsUnlockAllPrices);
stream->WriteValue<uint8>(gCheatsBuildInPauseMode);
stream->WriteValue<uint8>(gCheatsIgnoreRideIntensity);
stream->WriteValue<uint8>(gCheatsDisableVandalism);
stream->WriteValue<uint8>(gCheatsDisableLittering);
stream->WriteValue<uint8>(gCheatsNeverendingMarketing);
stream->WriteValue<uint8>(gCheatsFreezeClimate);
stream->WriteValue<uint8>(gCheatsDisablePlantAging);
stream->WriteValue<uint8>(gCheatsAllowArbitraryRideTypeChanges);
result = true;
}
catch (const Exception &)
{
}
return result;
}
void Network::Client_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet)
{
const char* text = packet.ReadString();
@ -1955,19 +2070,6 @@ void Network::Client_Handle_GAMEINFO(NetworkConnection& connection, NetworkPacke
network_chat_show_server_greeting();
}
namespace Convert
{
uint16 HostToNetwork(uint16 value)
{
return htons(value);
}
uint16 NetworkToHost(uint16 value)
{
return ntohs(value);
}
}
sint32 network_init()
{
return gNetwork.Init();
@ -2456,8 +2558,16 @@ void network_send_password(const char* password)
log_error("Private key %s missing! Restart the game to generate it.", keyPath);
return;
}
SDL_RWops *privkey = SDL_RWFromFile(keyPath, "rb");
gNetwork._key.LoadPrivate(privkey);
try
{
auto fs = FileStream(keyPath, FILE_MODE_OPEN);
gNetwork._key.LoadPrivate(&fs);
}
catch (Exception)
{
log_error("Error reading private key from %s.", keyPath);
return;
}
const std::string pubkey = gNetwork._key.PublicKeyString();
size_t sigsize;
char *signature;

View File

@ -67,7 +67,6 @@ extern "C" {
#include <vector>
#include <map>
#include <openssl/evp.h>
#include <SDL.h>
#include "../core/Json.hpp"
#include "../core/Nullable.hpp"
#include "NetworkConnection.h"
@ -174,6 +173,9 @@ private:
std::string GenerateAdvertiseKey();
void SetupDefaultGroups();
bool LoadMap(IStream * stream);
bool SaveMap(IStream * stream, const std::vector<const ObjectRepositoryItem *> &objects) const;
struct GameCommand
{
GameCommand(uint32 t, uint32* args, uint8 p, uint8 cb) {
@ -211,7 +213,7 @@ private:
INetworkServerAdvertiser * _advertiser = nullptr;
uint32 server_connect_time = 0;
uint8 default_group = 0;
SDL_RWops *_chatLogStream = nullptr;
IStream * _chatLogStream = nullptr;
std::string _chatLogPath;
uint32 game_commands_processed_this_tick = 0;
@ -245,15 +247,9 @@ private:
void Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet);
void Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet);
uint8 * save_for_network(SDL_RWops *buffer, size_t &out_size, const std::vector<const ObjectRepositoryItem *> &objects) const;
uint8 * save_for_network(size_t &out_size, const std::vector<const ObjectRepositoryItem *> &objects) const;
};
namespace Convert
{
uint16 HostToNetwork(uint16 value);
uint16 NetworkToHost(uint16 value);
}
#endif // __cplusplus
#else /* DISABLE_NETWORK */
#define NETWORK_STREAM_ID "Multiplayer disabled"

View File

@ -107,7 +107,6 @@ assert_struct_size(rct_object_filters, 3);
extern const rct_object_entry_group object_entry_groups[];
void object_list_load();
bool object_read_and_load_entries(SDL_RWops* rw);
bool object_load_entries(rct_object_entry* entries);
bool object_saved_packed(SDL_RWops* rw, const rct_object_entry * entry);

View File

@ -18,8 +18,9 @@
#include "../core/FileStream.hpp"
#include "../core/Memory.hpp"
#include "../core/MemoryStream.h"
#include "../core/String.hpp"
#include "../core/Path.hpp"
#include "../core/String.hpp"
#include "../rct12/SawyerChunkReader.h"
#include "BannerObject.h"
#include "EntranceObject.h"
#include "FootpathItemObject.h"
@ -102,64 +103,40 @@ namespace ObjectFactory
}
}
static MemoryStream * GetDecodedChunkStream(IReadObjectContext * context, SDL_RWops * file)
{
size_t bufferSize = 0x600000;
void * buffer = Memory::Allocate<void>(bufferSize);
if (buffer == nullptr)
{
log_error("Unable to allocate data buffer.");
return nullptr;
}
bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize);
if (bufferSize == SIZE_MAX)
{
context->LogError(OBJECT_ERROR_BAD_ENCODING, "Unable to decode chunk.");
Memory::Free(buffer);
return nullptr;
}
else
{
buffer = Memory::Reallocate(buffer, bufferSize);
return new MemoryStream(buffer, bufferSize, MEMORY_ACCESS::READ | MEMORY_ACCESS::OWNER);
}
}
Object * CreateObjectFromLegacyFile(const utf8 * path)
{
log_verbose("CreateObjectFromLegacyFile(\"%s\")", path);
Object * result = nullptr;
SDL_RWops * file = SDL_RWFromFile(path, "rb");
if (file != nullptr)
try
{
rct_object_entry entry;
if (SDL_RWread(file, &entry, sizeof(entry), 1) == 1)
auto fs = FileStream(path, FILE_MODE_OPEN);
auto chunkReader = SawyerChunkReader(&fs);
rct_object_entry entry = fs.ReadValue<rct_object_entry>();
result = CreateObject(entry);
utf8 objectName[9] = { 0 };
object_entry_get_name_fixed(objectName, sizeof(objectName), &entry);
log_verbose(" entry: { 0x%08X, \"%s\", 0x%08X }", entry.flags, objectName, entry.checksum);
auto chunk = chunkReader.ReadChunk();
log_verbose(" size: %zu", chunk->GetLength());
auto chunkStream = MemoryStream(chunk->GetData(), chunk->GetLength());
auto readContext = ReadObjectContext(objectName);
ReadObjectLegacy(result, &readContext, &chunkStream);
if (readContext.WasError())
{
result = CreateObject(entry);
if (result != nullptr)
{
utf8 objectName[9] = { 0 };
Memory::Copy(objectName, entry.name, 8);
auto readContext = ReadObjectContext(objectName);
auto chunkStream = GetDecodedChunkStream(&readContext, file);
if (chunkStream != nullptr)
{
ReadObjectLegacy(result, &readContext, chunkStream);
delete chunkStream;
}
if (readContext.WasError())
{
Console::Error::WriteLine("Error reading object: '%s'", path);
delete result;
result = nullptr;
}
}
throw Exception("Object has errors");
}
SDL_RWclose(file);
}
catch (Exception)
{
Console::Error::WriteLine("Unable to open or read '%s'", path);
delete result;
result = nullptr;
}
return result;
}
@ -190,8 +167,7 @@ namespace ObjectFactory
Object * CreateObject(const rct_object_entry &entry)
{
Object * result = nullptr;
Object * result;
uint8 objectType = entry.flags & 0x0F;
switch (objectType) {
case OBJECT_TYPE_RIDE:
@ -227,8 +203,9 @@ namespace ObjectFactory
case OBJECT_TYPE_SCENARIO_TEXT:
result = new StexObject(entry);
break;
default:
throw Exception("Invalid object type");
}
return result;
}
}

View File

@ -127,20 +127,6 @@ void object_create_identifier_name(char* string_buffer, size_t size, const rct_o
snprintf(string_buffer, size, "%.8s/%4X%4X", object->name, object->flags, object->checksum);
}
/**
*
* rct2: 0x006AA0C6
*/
bool object_read_and_load_entries(SDL_RWops* rw)
{
// Read all the object entries
rct_object_entry *entries = malloc(OBJECT_ENTRY_COUNT * sizeof(rct_object_entry));
sawyercoding_read_chunk_with_size(rw, (uint8*)entries, OBJECT_ENTRY_COUNT * sizeof(rct_object_entry));
bool result = object_load_entries(entries);
free(entries);
return result;
}
/**
*
* rct2: 0x006A9DA2

View File

@ -18,6 +18,7 @@
#include "crash.h"
#ifdef USE_BREAKPAD
#include <memory>
#include <stdio.h>
#if defined(__WINDOWS__)
@ -28,13 +29,16 @@
#error Breakpad support not implemented yet for this platform
#endif
extern "C" {
extern "C"
{
#include "../localisation/language.h"
#include "../scenario/scenario.h"
#include "platform.h"
}
#include "../core/Console.hpp"
#include "../core/Exception.hpp"
#include "../rct2/S6Exporter.h"
#define WSZ(x) L"" x
@ -86,21 +90,25 @@ static bool OnCrash(const wchar_t * dumpPath,
wprintf(L"Version: %s\n", WSZ(OPENRCT2_VERSION));
wprintf(L"Commit: %s\n", _wszCommitSha1Short);
utf8 * saveFilePathUTF8 = widechar_to_utf8(saveFilePath);
SDL_RWops * rw = SDL_RWFromFile(saveFilePathUTF8, "wb+");
free(saveFilePathUTF8);
bool savedGameDumped = false;
if (rw != NULL) {
scenario_save(rw, 0x80000000);
utf8 * saveFilePathUTF8 = widechar_to_utf8(saveFilePath);
try
{
auto exporter = std::make_unique<S6Exporter>();
exporter->Export();
exporter->SaveGame(saveFilePathUTF8);
savedGameDumped = true;
SDL_RWclose(rw);
}
catch (const Exception &)
{
}
free(saveFilePathUTF8);
if (gOpenRCT2SilentBreakpad)
{
return succeeded;
}
constexpr const wchar_t * MessageFormat = L"A crash has occurred and a dump was created at\n%s.\n\nPlease file an issue with OpenRCT2 on GitHub, and provide the dump and saved game there.\n\nVersion: %s\nCommit: %s";
wchar_t message[MAX_PATH * 2];
swprintf_s(message,

View File

@ -396,61 +396,6 @@ uint32 S6Exporter::GetLoanHash(money32 initialCash, money32 bankLoan, uint32 max
return value;
}
// Save game state without modifying any of the state for multiplayer
sint32 scenario_save_network(SDL_RWops * rw, const std::vector<const ObjectRepositoryItem *> &objects)
{
viewport_set_saved_view();
bool result = false;
auto s6exporter = new S6Exporter();
try
{
auto rwStream = FileStream(rw, FILE_MODE_WRITE);
s6exporter->ExportObjectsList = objects;
s6exporter->Export();
s6exporter->SaveGame(&rwStream);
result = true;
}
catch (const Exception &)
{
}
delete s6exporter;
if (!result)
{
return 0;
}
// Write other data not in normal save files
SDL_RWwrite(rw, gSpriteSpatialIndex, 0x10001 * sizeof(uint16), 1);
SDL_WriteLE32(rw, gGamePaused);
SDL_WriteLE32(rw, _guestGenerationProbability);
SDL_WriteLE32(rw, _suggestedGuestMaximum);
SDL_WriteU8(rw, gCheatsSandboxMode);
SDL_WriteU8(rw, gCheatsDisableClearanceChecks);
SDL_WriteU8(rw, gCheatsDisableSupportLimits);
SDL_WriteU8(rw, gCheatsDisableTrainLengthLimit);
SDL_WriteU8(rw, gCheatsEnableChainLiftOnAllTrack);
SDL_WriteU8(rw, gCheatsShowAllOperatingModes);
SDL_WriteU8(rw, gCheatsShowVehiclesFromOtherTrackTypes);
SDL_WriteU8(rw, gCheatsFastLiftHill);
SDL_WriteU8(rw, gCheatsDisableBrakesFailure);
SDL_WriteU8(rw, gCheatsDisableAllBreakdowns);
SDL_WriteU8(rw, gCheatsUnlockAllPrices);
SDL_WriteU8(rw, gCheatsBuildInPauseMode);
SDL_WriteU8(rw, gCheatsIgnoreRideIntensity);
SDL_WriteU8(rw, gCheatsDisableVandalism);
SDL_WriteU8(rw, gCheatsDisableLittering);
SDL_WriteU8(rw, gCheatsNeverendingMarketing);
SDL_WriteU8(rw, gCheatsFreezeClimate);
SDL_WriteU8(rw, gCheatsDisablePlantAging);
SDL_WriteU8(rw, gCheatsAllowArbitraryRideTypeChanges);
gfx_invalidate_screen();
return 1;
}
extern "C"
{
enum {

View File

@ -30,8 +30,6 @@ extern "C"
interface IStream;
struct ObjectRepositoryItem;
sint32 scenario_save_network(SDL_RWops* rw, const std::vector<const ObjectRepositoryItem *> &objects);
/**
* Class to export RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6).
*/

View File

@ -486,42 +486,6 @@ extern "C"
return result;
}
bool scenario_load_rw(SDL_RWops * rw)
{
bool result = false;
auto stream = FileStream(rw, FILE_MODE_OPEN);
auto s6Importer = new S6Importer();
try
{
s6Importer->LoadFromStream(&stream, true);
s6Importer->Import();
game_fix_save_vars();
sprite_position_tween_reset();
result = true;
}
catch (ObjectLoadException)
{
gErrorType = ERROR_TYPE_FILE_LOAD;
gErrorStringId = STR_GAME_SAVE_FAILED;
}
catch (IOException)
{
gErrorType = ERROR_TYPE_FILE_LOAD;
gErrorStringId = STR_GAME_SAVE_FAILED;
}
catch (Exception)
{
gErrorType = ERROR_TYPE_FILE_LOAD;
gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA;
}
delete s6Importer;
gScreenAge = 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
return result;
}
/**
*
* rct2: 0x00676053
@ -561,63 +525,4 @@ extern "C"
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
return result;
}
sint32 game_load_network(SDL_RWops* rw)
{
bool result = false;
auto stream = FileStream(rw, FILE_MODE_OPEN);
auto s6Importer = new S6Importer();
try
{
s6Importer->LoadFromStream(&stream, false);
s6Importer->Import();
sprite_position_tween_reset();
result = true;
}
catch (const ObjectLoadException &)
{
}
catch (const Exception &)
{
}
delete s6Importer;
if (!result)
{
return 0;
}
// Read checksum
uint32 checksum;
SDL_RWread(rw, &checksum, sizeof(uint32), 1);
// Read other data not in normal save files
SDL_RWread(rw, gSpriteSpatialIndex, 0x10001 * sizeof(uint16), 1);
gGamePaused = SDL_ReadLE32(rw);
_guestGenerationProbability = SDL_ReadLE32(rw);
_suggestedGuestMaximum = SDL_ReadLE32(rw);
gCheatsSandboxMode = SDL_ReadU8(rw) != 0;
gCheatsDisableClearanceChecks = SDL_ReadU8(rw) != 0;
gCheatsDisableSupportLimits = SDL_ReadU8(rw) != 0;
gCheatsDisableTrainLengthLimit = SDL_ReadU8(rw) != 0;
gCheatsEnableChainLiftOnAllTrack = SDL_ReadU8(rw) != 0;
gCheatsShowAllOperatingModes = SDL_ReadU8(rw) != 0;
gCheatsShowVehiclesFromOtherTrackTypes = SDL_ReadU8(rw) != 0;
gCheatsFastLiftHill = SDL_ReadU8(rw) != 0;
gCheatsDisableBrakesFailure = SDL_ReadU8(rw) != 0;
gCheatsDisableAllBreakdowns = SDL_ReadU8(rw) != 0;
gCheatsUnlockAllPrices = SDL_ReadU8(rw) != 0;
gCheatsBuildInPauseMode = SDL_ReadU8(rw) != 0;
gCheatsIgnoreRideIntensity = SDL_ReadU8(rw) != 0;
gCheatsDisableVandalism = SDL_ReadU8(rw) != 0;
gCheatsDisableLittering = SDL_ReadU8(rw) != 0;
gCheatsNeverendingMarketing = SDL_ReadU8(rw) != 0;
gCheatsFreezeClimate = SDL_ReadU8(rw) != 0;
gCheatsDisablePlantAging = SDL_ReadU8(rw) != 0;
gCheatsAllowArbitraryRideTypeChanges = SDL_ReadU8(rw) != 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
return 1;
}
}

View File

@ -376,7 +376,6 @@ extern uint32 gLastAutoSaveUpdate;
extern const char *_scenarioFileName;
bool scenario_load_rw(SDL_RWops * rw);
sint32 scenario_load(const char *path);
sint32 scenario_load_and_play_from_path(const char *path);
void scenario_begin();

View File

@ -15,7 +15,6 @@
#pragma endregion
#include <vector>
#include <SDL.h>
#include "../common.h"
#include "../core/Collections.hpp"
#include "../core/Console.hpp"
@ -39,7 +38,7 @@
static std::vector<utf8 *> GetSaves(const utf8 * path);
static std::vector<utf8 *> GetSaves(IZipArchive * zip);
static std::vector<TitleCommand> LegacyScriptRead(utf8 * script, size_t scriptLength, std::vector<utf8 *> saves);
static void LegacyScriptGetLine(SDL_RWops * file, char * parts);
static void LegacyScriptGetLine(IStream * stream, char * parts);
static void * ReadScriptFile(const utf8 * path, size_t * outSize);
static utf8 * LegacyScriptWrite(TitleSequence * seq);
@ -392,10 +391,11 @@ static std::vector<utf8 *> GetSaves(IZipArchive * zip)
static std::vector<TitleCommand> LegacyScriptRead(utf8 * script, size_t scriptLength, std::vector<utf8 *> saves)
{
std::vector<TitleCommand> commands;
SDL_RWops * file = SDL_RWFromMem(script, (sint32)scriptLength);
do {
auto fs = MemoryStream(script, scriptLength);
do
{
char parts[3 * 128], *token, *part1, *part2;
LegacyScriptGetLine(file, parts);
LegacyScriptGetLine(&fs, parts);
token = &parts[0 * 128];
part1 = &parts[1 * 128];
@ -466,13 +466,12 @@ static std::vector<TitleCommand> LegacyScriptRead(utf8 * script, size_t scriptLe
{
commands.push_back(command);
}
} while (SDL_RWtell(file) < (sint32)scriptLength);
SDL_RWclose(file);
}
while (fs.GetPosition() < scriptLength);
return commands;
}
static void LegacyScriptGetLine(SDL_RWops * file, char * parts)
static void LegacyScriptGetLine(IStream * stream, char * parts)
{
for (sint32 i = 0; i < 3; i++)
{
@ -486,7 +485,7 @@ static void LegacyScriptGetLine(SDL_RWops * file, char * parts)
for (; part < 3;)
{
sint32 c = 0;
if (SDL_RWread(file, &c, 1, 1) != 1)
if (stream->TryRead(&c, 1) != 1)
{
c = EOF;
}

View File

@ -18,8 +18,6 @@
#include "../common.h"
struct SDL_RWops;
typedef struct TitleCommand
{
uint8 Type;

View File

@ -495,7 +495,7 @@ uint8 *util_zlib_inflate(uint8 *data, size_t data_in_size, size_t *data_out_size
* @return Returns a pointer to memory holding compressed data or NULL on failure.
* @note It is caller's responsibility to free() the returned pointer once done with it.
*/
uint8 *util_zlib_deflate(uint8 *data, size_t data_in_size, size_t *data_out_size)
uint8 *util_zlib_deflate(const uint8 *data, size_t data_in_size, size_t *data_out_size)
{
sint32 ret = Z_OK;
uLongf out_size = (uLongf)*data_out_size;

View File

@ -53,7 +53,7 @@ bool str_is_null_or_empty(const char *str);
void util_srand(sint32 source);
uint32 util_rand();
uint8 *util_zlib_deflate(uint8 *data, size_t data_in_size, size_t *data_out_size);
uint8 *util_zlib_deflate(const uint8 *data, size_t data_in_size, size_t *data_out_size);
uint8 *util_zlib_inflate(uint8 *data, size_t data_in_size, size_t *data_out_size);
#endif