/* * Original work: Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * RakNet License.txt file in the licenses directory of this source tree. An additional grant * of patent rights can be found in the RakNet Patents.txt file in the same directory. * * * Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt) * * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style * license found in the license.txt file in the root directory of this source tree. */ #include "slikenet/peerinterface.h" #include "slikenet/BitStream.h" #include "slikenet/GetTime.h" #include "slikenet/sleep.h" #include "slikenet/Gets.h" #include "slikenet/MessageIdentifiers.h" #include "slikenet/Kbhit.h" #include "slikenet/ReplicaManager3.h" #include "slikenet/peerinterface.h" #include "slikenet/NetworkIDManager.h" using namespace SLNet; // Purpose: UDP network communication // Required?: Yes RakPeerInterface *rakPeer; // Purpose: Game object replication // Required?: No, but manages object replication automatically. Some form of this is required for almost every game ReplicaManager3 *g_replicaManager3; // Purpose: Lookup game objects given ID. Used by ReplicaManager3 // Required?: Required to use ReplicaManager3, and some form of this is required for almost every game NetworkIDManager *networkIDManager; bool runningAsServer; class User : public Replica3 { public: User() { score=0; } virtual ~User() { } virtual void WriteAllocationID(SLNet::Connection_RM3 *destinationConnection, SLNet::BitStream *allocationIdBitstream) const { // unused parameters (void)destinationConnection; allocationIdBitstream->Write("User"); } virtual RM3ConstructionState QueryConstruction(SLNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3) { // unused parameters (void)replicaManager3; return QueryConstruction_ServerConstruction(destinationConnection, runningAsServer); } virtual bool QueryRemoteConstruction(SLNet::Connection_RM3 *sourceConnection) { return QueryRemoteConstruction_ServerConstruction(sourceConnection, runningAsServer); } static void SerializeToBitStream(User *user, BitStream *bitStream) { bitStream->Write(user->score); bitStream->Write(user->username); bitStream->Write(user->guid); } static void DeserializeToBitStream(User *user, BitStream *bitStream) { bitStream->Read(user->score); bitStream->Read(user->username); bitStream->Read(user->guid); } virtual void SerializeConstruction(SLNet::BitStream *constructionBitstream, SLNet::Connection_RM3 *destinationConnection) { // unused parameters (void)destinationConnection; SerializeToBitStream(this, constructionBitstream); } virtual bool DeserializeConstruction(SLNet::BitStream *constructionBitstream, SLNet::Connection_RM3 *sourceConnection) { // unused parameters (void)sourceConnection; DeserializeToBitStream(this, constructionBitstream); if (guid==rakPeer->GetMyGUID()) printf("My user created with name %s and score %i\n", username.C_String(), score); else printf("Another user created with name %s and score %i\n", username.C_String(), score); return true; } virtual void SerializeDestruction(SLNet::BitStream *destructionBitstream, SLNet::Connection_RM3 *destinationConnection) { // unused parameters (void)destructionBitstream; (void)destinationConnection; } virtual bool DeserializeDestruction(SLNet::BitStream *destructionBitstream, SLNet::Connection_RM3 *sourceConnection) { // unused parameters (void)destructionBitstream; (void)sourceConnection; return true; } virtual SLNet::RM3ActionOnPopConnection QueryActionOnPopConnection(SLNet::Connection_RM3 *droppedConnection) const { if (runningAsServer) return QueryActionOnPopConnection_Server(droppedConnection); else return QueryActionOnPopConnection_Client(droppedConnection); } virtual void DeallocReplica(SLNet::Connection_RM3 *sourceConnection) { // unused parameters (void)sourceConnection; delete this; } virtual SLNet::RM3QuerySerializationResult QuerySerialization(SLNet::Connection_RM3 *destinationConnection) { return QuerySerialization_ServerSerializable(destinationConnection, runningAsServer); } virtual RM3SerializationResult Serialize(SLNet::SerializeParameters *serializeParameters) { SerializeToBitStream(this, &serializeParameters->outputBitstream[0]); return RM3SR_BROADCAST_IDENTICALLY; } virtual void Deserialize(SLNet::DeserializeParameters *deserializeParameters) { if (deserializeParameters->bitstreamWrittenTo[0]) DeserializeToBitStream(this, &deserializeParameters->serializationBitstream[0]); } static void DeleteUserWithGuid(RakNetGUID guid) { for (unsigned int i=0; i < g_replicaManager3->GetReplicaCount(); i++) { User *u = (User *)g_replicaManager3->GetReplicaAtIndex(i); if (u->guid==guid) { u->BroadcastDestruction(); g_replicaManager3->Dereference(u); delete u; break; } } } virtual void PreDestruction(SLNet::Connection_RM3 *sourceConnection) { // unused parameters (void)sourceConnection; if (guid==rakPeer->GetMyGUID()) printf("My user destroyed with name %s and score %i\n", username.C_String(), score); else printf("Another user destroyed with name %s and score %i\n", username.C_String(), score); } int score; RakString username; RakNetGUID guid; }; // Required by ReplicaManager3. Acts as a class factory for Replica3 derived instances class SampleConnectionRM3 : public Connection_RM3 { public: SampleConnectionRM3(const SystemAddress &_systemAddress, RakNetGUID _guid) : Connection_RM3(_systemAddress, _guid) { } virtual ~SampleConnectionRM3() { } virtual Replica3 *AllocReplica(SLNet::BitStream *allocationIdBitstream, ReplicaManager3 *replicaManager3) { // unused parameters (void)replicaManager3; RakString objectType; // Types are written by WriteAllocationID() allocationIdBitstream->Read(objectType); if (objectType=="User") return new User; RakAssert("Unknown type in AllocReplica" && 0); return 0; } }; // Required by ReplicaManager3. Acts as a class factory for Connection_RM3 derived instances class SampleRM3 : public ReplicaManager3 { public: SampleRM3() { } virtual ~SampleRM3() { } virtual Connection_RM3* AllocConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID) const { return new SampleConnectionRM3(systemAddress,rakNetGUID); } virtual void DeallocConnection(Connection_RM3 *connection) const { delete connection; } }; int serverMain(void); int clientMain(void); int main(void) { rakPeer= SLNet::RakPeerInterface::GetInstance(); networkIDManager = NetworkIDManager::GetInstance(); g_replicaManager3=new SampleRM3; // --------------------------------------------------------------------------------------------------------------------- // Attach plugins // --------------------------------------------------------------------------------------------------------------------- rakPeer->AttachPlugin(g_replicaManager3); // Tell ReplicaManager3 which networkIDManager to use for object lookup, used for automatic serialization g_replicaManager3->SetNetworkIDManager(networkIDManager); printf("(S)erver or (C)lient?\n"); int ch = _getch(); if (ch=='s' || ch=='S') return serverMain(); else return clientMain(); } int serverMain(void) { runningAsServer=true; SLNet::SocketDescriptor sd; sd.port=60000; SLNET_VERIFY(rakPeer->Startup(8, &sd, 1) == RAKNET_STARTED); rakPeer->SetMaximumIncomingConnections(8); rakPeer->SetTimeoutTime(30000, SLNet::UNASSIGNED_SYSTEM_ADDRESS); printf("Waiting for connections\n"); Packet *packet; for(;;) { for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive()) { switch (packet->data[0]) { case ID_NEW_INCOMING_CONNECTION: printf("ID_NEW_INCOMING_CONNECTION from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString()); break; case ID_CONNECTION_REQUEST_ACCEPTED: printf("ID_CONNECTION_REQUEST_ACCEPTED from %s,guid=%s\n", packet->systemAddress.ToString(true), packet->guid.ToString()); break; case ID_CONNECTION_LOST: printf("ID_CONNECTION_LOST from %s,guid=%s\n", packet->systemAddress.ToString(true), packet->guid.ToString()); User::DeleteUserWithGuid(packet->guid); break; case ID_DISCONNECTION_NOTIFICATION: printf("ID_DISCONNECTION_NOTIFICATION from %s,guid=%s\n", packet->systemAddress.ToString(true), packet->guid.ToString()); User::DeleteUserWithGuid(packet->guid); break; // Login case ID_USER_PACKET_ENUM: { BitStream bsIn(packet->data, packet->length, false); bsIn.IgnoreBytes(sizeof(MessageID)); RakString username; bsIn.Read(username); printf("Accepting login from %s\n", username.C_String()); User *newUser = new User; newUser->score=0; newUser->guid=packet->guid; newUser->username = username; g_replicaManager3->Reference(newUser); } break; } } RakSleep(30); } } int clientMain(void) { runningAsServer=false; SLNet::SocketDescriptor sd; sd.port=0; SLNET_VERIFY(rakPeer->Startup(1, &sd, 1) == RAKNET_STARTED); rakPeer->SetTimeoutTime(30000, SLNet::UNASSIGNED_SYSTEM_ADDRESS); rakPeer->Connect("127.0.0.1", 60000, 0, 0); printf("Connecting to server...\n"); Packet *packet; for(;;) { for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive()) { switch (packet->data[0]) { case ID_NEW_INCOMING_CONNECTION: printf("ID_NEW_INCOMING_CONNECTION from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString()); break; case ID_CONNECTION_REQUEST_ACCEPTED: { printf("ID_CONNECTION_REQUEST_ACCEPTED from %s,guid=%s\n", packet->systemAddress.ToString(true), packet->guid.ToString()); printf("Logging in...\n"); BitStream bsOut; // Login bsOut.WriteCasted(ID_USER_PACKET_ENUM); RakString username("User %s", rakPeer->GetMyGUID().ToString()); bsOut.Write(username); rakPeer->Send(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->guid, false); } break; case ID_CONNECTION_LOST: printf("ID_CONNECTION_LOST from %s,guid=%s\n", packet->systemAddress.ToString(true), packet->guid.ToString()); break; case ID_DISCONNECTION_NOTIFICATION: printf("ID_DISCONNECTION_NOTIFICATION from %s,guid=%s\n", packet->systemAddress.ToString(true), packet->guid.ToString()); break; } } RakSleep(30); } }