diff --git a/.gitea/workflows/autobuild.yaml b/.gitea/workflows/autobuild.yaml index 0a8ccc1..e37d1c2 100644 --- a/.gitea/workflows/autobuild.yaml +++ b/.gitea/workflows/autobuild.yaml @@ -33,7 +33,7 @@ jobs: rm raylib -r rm yaml-cpp -r - wget https://github.com/zpl-c/enet/archive/refs/heads/master.zip + wget https://github.com/lsalzman/enet/archive/refs/heads/master.zip unzip master.zip mv enet-master enet rm master.zip diff --git a/data/resources/nekit.png b/data/resources/nekit.png new file mode 100644 index 0000000..baa44a5 Binary files /dev/null and b/data/resources/nekit.png differ diff --git a/data/resources/player.png b/data/resources/player.png index baa44a5..25e3a5a 100644 Binary files a/data/resources/player.png and b/data/resources/player.png differ diff --git a/src/helpers/chunks.cpp b/src/helpers/chunks.cpp index 47cc0f8..54dd163 100644 --- a/src/helpers/chunks.cpp +++ b/src/helpers/chunks.cpp @@ -427,12 +427,12 @@ void TickBlock(Chunk world[], int wx, int wy, int wz) { if(tile == BLOCK_SAND) { if(GetBlock(world, wx, wy-1, wz) == 0) { SetBlockNetwork(world, wx, wy, wz, 0); - Entity temp = NewEntity(); + Entity temp = NewEntity(0); temp.type = 4; temp.position = (Vector3){wx, wy, wz}; temp.velocity = {0, 0, 0}; temp.data[1] = BLOCK_SAND; - AddEntity(temp); + //AddEntity(temp); } } } @@ -442,32 +442,7 @@ void TickChunk(Chunk *chunk, Chunk *world, int wx, int wz) { { for (int z = 0; z < CHUNK_SIZE; z++) { - int tile = fetch_block_ptr(chunk, x, y, z); - if(tile == BLOCK_SAND) { - if(fetch_block_ptr(chunk, x, y-1, z) == 0) { - SetBlockChunk(chunk, x, y, z, 0); - Entity temp = NewEntity(); - temp.type = 4; - temp.position = (Vector3){((int)wx * CHUNK_SIZE + x), y, ((int)wz * CHUNK_SIZE + z)}; - temp.velocity = {0, 0, 0}; - temp.data[1] = BLOCK_SAND; - AddEntity(temp); - chunk->isDirty = true; - } - } - if(false) { // tile == BLOCK_WATERS - int rx = GetRandomValue(-1, 1); - int rz = GetRandomValue(-1, 1); - for (int _y = 0; _y >= -1; _y--) - { - if(GetBlock(world, wx+x+rx, y+_y, wz+z+rz) == 0) { - SetBlockChunk(chunk, x, y+_y, z, 0); - SetBlock(world, wx+x+rx, y+_y, wz+z+rz, BLOCK_WATERS); - chunk->isDirty = true; - continue; - } - } - } + TickBlock(world, x, y, z); } } } diff --git a/src/helpers/common.hpp b/src/helpers/common.hpp index 04ae25f..8fddc0a 100644 --- a/src/helpers/common.hpp +++ b/src/helpers/common.hpp @@ -62,12 +62,16 @@ #define NET_ARG_PLRREG 0x07 // Same as ECHOMOVE, used as an answer to REQPLAYERS #define NET_ARG_ECHOYAW 0x08 // Byte 1 - ID, byte 2 - yaw #define NET_ARG_MESSAGEE 0x09 // Byte 1 - sender ID, byte 2 - length, rest is message (128b max) +#define NET_ARG_ENTITYSPAWN 0x0A // uint16_t entityWorldID, uint8_t entityTypeID, uint16_t x, uint16_t y, uint16_t z, uint8_t data[8] +#define NET_ARG_ENTITYMOVE 0x0B // uint16_t entityWorldID, uint16_t x, uint16_t y, uint16_t z +#define NET_ARG_PLRSKIN 0x0C // Byte 1 - ID, bytes 2-3 - size, rest is skin #define NET_ARG_PLAYERMOVE 0x80 // Byte 1-2 - player X, byte 3-4 - player Y, byte 5-6 - player Z, byte 7 - player yaw #define NET_ARG_BLOCKDELTA 0x81 // Block X, block Y, block Z, block type #define NET_ARG_REQWORLD 0x82 // No additional data #define NET_ARG_REQPLAYERS 0x83 // No additional data #define NET_ARG_PLAYERYAW 0x84 // Byte 1 - yaw #define NET_ARG_MESSAGEC 0x85 // All is message (64b max) +#define NET_ARG_PLRSKINSET 0x86 // Byte 1 - ID, bytes 2-3 - size, rest is skin #define NET_ERROR_DSCN 0x00 #define NET_ERROR_NOTFOUND 0x01 #define NET_ERROR_FAILED 0x02 @@ -79,6 +83,7 @@ #define TPS_DIV 1.0 / TPS #define RENDER_DISTANCE 16 #define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE +#define PIXUNIT 1.0f / 16.0f #define MAX_HP 100 #define PATH_APPEND "resources/" #define PATH_APPEND_USER "user/" @@ -201,17 +206,18 @@ struct Vector3I { }; typedef struct Entity Entity; struct Entity { + uint16_t id; uint8_t type; - uint8_t id; uint8_t damage_flash; - uint8_t data[16]; + uint8_t data[4]; + uint8_t data_sv[8]; + bool free; float smoothing; float health; float lifetime; Vector3 position; Vector3 velocity; unsigned short yaw; - bool free; }; typedef struct NetPlayer NetPlayer; struct NetPlayer { @@ -223,6 +229,9 @@ struct NetPlayer { float x; float y; float z; + std::string nickname; + Texture2D texture; + std::vector skin; }; typedef struct MemInfo MemInfo; struct MemInfo { @@ -321,49 +330,34 @@ bool Debug_GetProcessMemory(MemInfo&out); #if !defined(WIN32) bool Debug_GetProcessMemory(MemInfo&out); #endif -#if !defined(SERVER) extern Camera camera; -#endif extern Camera3D camera; #if !defined(SERVER) extern Camera camera; -extern Font fnt; -extern Font fnt; -extern Texture2D terrain; #endif +extern Font fnt; +#if !defined(SERVER) +extern Font fnt; +#endif +extern Texture2D terrain; extern Texture2D terrain; #if !defined(SERVER) extern Texture2D terrain; extern Texture2D terrain; -extern Texture2D playerTex; -extern Texture2D playerTex; +#endif +extern Texture2D nekitTex; extern Texture2D bomb; extern Sound nekit_idle; void EntitiesInit(); extern bool online; +#if !defined(SERVER) extern bool online; #endif -#if !(!defined(SERVER)) -extern bool online; -#endif -#if !defined(SERVER) -extern Vector3 player_position; -#endif -extern Vector3 player_position; -#if !defined(SERVER) -extern Vector3 player_velocity; -#endif -extern Vector3 player_velocity; -#if !defined(SERVER) void TakeDamage(float amount); void SetBlockNetwork(Chunk world[],int bx,int by,int bz,int t); -#endif -Entity NewEntity(); -void AddEntity(Entity ent); -void UpdateEntities(Chunk world[],float dt); +Entity NewEntity(int id); extern float globalCounter; #if !defined(SERVER) -void DrawEntities(float dt); extern bool swap_mouse; bool InputGetLMB(); bool InputGetLMBDown(); @@ -378,6 +372,7 @@ extern int currentlySelected; extern GameState state; extern Texture2D cubemap; int TryConnect(const char *hostname); +void InitSingleplayer(); void GameModeCleanup(); void DrawBackground(); void InitMenu(); @@ -395,6 +390,7 @@ void DrawMainMenu(); void _LoadWorld(const char *path); void DrawWorldSelect(); void DrawMultiplayer(); +void ExitSingleplayer(); void DrawPauseMenu(); extern char bufferChat[MAX_MESSAGE_LENGTH]; char *DrawChat(); @@ -586,6 +582,7 @@ extern InventoryItem inventory[INVENTORY_SIZE]; #endif extern InventoryItem inventory[INVENTORY_SIZE]; #if !defined(SERVER) +extern Texture2D playerTex; extern bool inventoryOpen; extern InventoryItem *movingItem; void DrawItem(InventoryItem item,int x,int y); @@ -612,6 +609,8 @@ extern float player_health; extern float player_attack_time; extern float player_place_time; extern float player_break_parts_time; +extern Vector3 player_position; +extern Vector3 player_velocity; void SavePlayerData(); bool LoadPlayerData(); void MS_PlaySound(Sound src,float pitch,float volume,Vector3 position); diff --git a/src/helpers/entities.cpp b/src/helpers/entities.cpp index 0292d00..ecfcf18 100644 --- a/src/helpers/entities.cpp +++ b/src/helpers/entities.cpp @@ -9,42 +9,32 @@ #include #include -#define PIXUNIT 1.0f / 16.0f - -#ifndef SERVER extern Camera camera; extern Font fnt; extern Texture2D terrain; -Texture2D playerTex; +Texture2D nekitTex; Texture2D bomb; Sound nekit_idle; void EntitiesInit() { - playerTex = LoadTexture(Pathify("player.png")); + nekitTex = LoadTexture(Pathify("nekit.png")); bomb = LoadTexture(Pathify("bomb.png")); nekit_idle = LoadSound(Pathify("sound/nekit/idle.ogg")); } extern bool online; -extern Vector3 player_position; -extern Vector3 player_velocity; void TakeDamage(float amount); void SetBlockNetwork(Chunk world[], int bx, int by, int bz, int t); -#else - bool online = true; -#endif -std::list entities; - -Entity NewEntity() { +Entity NewEntity(int id) { Entity ent; - ent.id = entities.size(); + ent.id = id; ent.type = 0; ent.yaw = 0; ent.free = false; return ent; } -void AddEntity(Entity ent) { +void AddEntity(std::list entities, Entity ent) { entities.push_back(ent); } @@ -67,7 +57,7 @@ static void UpdateEntityPhysics(Chunk world[], Entity& ent, float dt) { ent.velocity = velocityTgt; ent.position = final; } -void UpdateEntities(Chunk world[], float dt) { +void UpdateEntities(std::list entities, Chunk world[], float dt) { if(entities.size() > 0) { int idx = 0; for(Entity& ent : entities) { @@ -93,9 +83,6 @@ void UpdateEntities(Chunk world[], float dt) { Vector3 direction = Vector3Normalize(Vector3Subtract(target, ent.position)); float degYaw = -atan2f(direction.z, direction.x) * RAD2DEG + 90; - if(GetRandomValue(0, 2000) == 0) { - MS_PlaySound(nekit_idle, GetRandomValue(75,125)/100.0f, 1.0f, ent.position); - } ent.velocity = Vector3Add(ent.velocity, (Vector3){direction.x * 20.0f, 0, direction.z * 20.0f}*dt); if(GetBlock(world, (int)ent.position.x, (int)ent.position.y-1, (int)ent.position.z) && GetRandomValue(0, 100) == 0) { ent.velocity.y += 10.0f; @@ -110,54 +97,8 @@ void UpdateEntities(Chunk world[], float dt) { if(ent.health < 0.1f) { ent.free = true; } - if(ent.data[2] < 90) - ent.data[2]++; ent.yaw = (unsigned short)(degYaw/360.0f*65535); } - /*if(ent.type == 3) { - Vector3 velocityTgt = Vector3Clamp(Vector3Add(ent.velocity, {0, -dt * 20.0f, 0}), {-30.0f, -30.0f, -30.0f}, {30.0f, 30.0f, 30.0f}); - - Vector3 tgt = Vector3Add(ent.position, Vector3Scale(velocityTgt, dt)); - Vector3 final = ent.position; - if(!GetBlock(world, (int)tgt.x, (int)final.y, (int)final.z)) { - final.x = tgt.x; - } - if(!GetBlock(world, (int)final.x, (int)tgt.y, (int)final.z)) { - final.y = tgt.y; - } - else { - velocityTgt.y = -velocityTgt.y / 2.0f; - velocityTgt = Vector3Scale(velocityTgt, 0.9f); - } - if(!GetBlock(world, (int)final.x, (int)final.y, (int)tgt.z)) { - final.z = tgt.z; - } - Entity* entp = &ent; - entp->yaw = 0; - entp->position = final; - entp->velocity = velocityTgt; - if(ent.lifetime > 5.0f) { - int radius = 3; - for (int x = -radius; x < radius; x++) - { - for (int y = -radius; y < radius; y++) - { - for (int z = -radius; z < radius; z++) - { - if(Vector3Distance({final.x + x, final.y + y, final.z + z}, final) <= radius) { - if(!CheckOOBWorld(final.x + x, final.y + y, final.z + z)) { - #ifndef SERVER - SetBlockNetwork(world, final.x + x, final.y + y, final.z + z, 0); - #endif - } - } - } - } - } - entp->free = true; - } - idx++; - }*/ if(ent.type == 4) { Vector3 velocityTgt = Vector3Clamp(Vector3Add(ent.velocity, {0, -dt * 20.0f, 0}), {-30.0f, -30.0f, -30.0f}, {30.0f, 30.0f, 30.0f}); @@ -184,7 +125,7 @@ void UpdateEntities(Chunk world[], float dt) { } Entity* entp = &ent; if(hit) { - SetBlockNetwork(world, (int)ent.position.x, (int)ent.position.y, (int)ent.position.z, ent.data[1]); + SetBlockNetwork(world, (int)ent.position.x, (int)ent.position.y, (int)ent.position.z, ent.data_sv[1]); entp->free = true; } entp->yaw = 0; @@ -203,8 +144,8 @@ void UpdateEntities(Chunk world[], float dt) { } } float globalCounter = 0; -#ifndef SERVER -void DrawEntities(float dt) { + +void DrawEntities(std::list entities, float dt) { globalCounter += dt; for(Entity& ent : entities) { ent.smoothing += dt; @@ -281,83 +222,7 @@ void DrawEntities(float dt) { rlPopMatrix(); } if(ent.type == 1) { - Color color = WHITE; - Vector3 posLerp = Vector3Add(ent.position, {-0.5f, -0.1f, -0.5f}); - - float time = ent.lifetime * 4.0f; - float armWave0 = sinf(time * PI); - float armWave1 = -abs(cosf(time * PI)); - float headWave = cosf(time * PI); - posLerp = Vector3Add(posLerp, {0, abs(sinf(time * PI)) * 0.1f, 0}); - Vector3 headPivot = Vector3Add(posLerp, (Vector3){0, 16*PIXUNIT, 0}); - float yaw = -ent.yaw / 65535.0f * 360.0f - 90; - - rlPushMatrix(); - rlTranslatef(posLerp.x, posLerp.y, posLerp.z); - rlRotatef(yaw, 0, 1, 0); - rlTranslatef(-posLerp.x, -posLerp.y, -posLerp.z); - - // - - rlPushMatrix(); - rlTranslatef(headPivot.x, headPivot.y, headPivot.z); - rlRotatef(25.0f * armWave0, 1, 0, 0); - rlRotatef(25.0f * headWave, 0, 0, 1); - // Head - DrawCubeTexture(playerTex, {0, 4*PIXUNIT, 0}, 8*PIXUNIT, 8*PIXUNIT, 8*PIXUNIT, WHITE, 8, 8, 8, 8); - rlPopMatrix(); - - Vector3 leftPivot = Vector3Add(posLerp, (Vector3){-6*PIXUNIT, 1.25f - 5*PIXUNIT, 0}); - Vector3 rightPivot = Vector3Add(posLerp, (Vector3){6*PIXUNIT, 1.25f - 5*PIXUNIT, 0}); - - rlPushMatrix(); - rlTranslatef(leftPivot.x, leftPivot.y, leftPivot.z); - rlRotatef(45.0f * armWave0, 1, 0, 0); - rlRotatef(45.0f * armWave1, 0, 0, 1); - DrawCubeTexture(playerTex, (Vector3){0, -6*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4); - rlPopMatrix(); - - rlPushMatrix(); - rlTranslatef(rightPivot.x, rightPivot.y, rightPivot.z); - rlRotatef(-45.0f * armWave0, 1, 0, 0); - rlRotatef(-45.0f * armWave1, 0, 0, 1); - DrawCubeTexture(playerTex, (Vector3){0, -6*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4); - rlPopMatrix(); - - Vector3 body = Vector3Add(posLerp, {0, 1.25f - 10*PIXUNIT, 0}); - - rlPushMatrix(); - rlTranslatef(body.x, body.y, body.z); - DrawCubeTexture(playerTex, Vector3Zero(), 8*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 20, 20, 8, 4); - rlPopMatrix(); - - leftPivot = Vector3Add(posLerp, (Vector3){-2*PIXUNIT, 1.25f - 14*PIXUNIT, 0}); - rightPivot = Vector3Add(posLerp, (Vector3){2*PIXUNIT, 1.25f - 14*PIXUNIT, 0}); - - rlPushMatrix(); - rlTranslatef(leftPivot.x, leftPivot.y, leftPivot.z); - rlRotatef(-45.0f * armWave0, 1, 0, 0); - DrawCubeTexture(playerTex, {0*PIXUNIT, -8*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 4, 20, 4, 4); - rlPopMatrix(); - - rlPushMatrix(); - rlTranslatef(rightPivot.x, rightPivot.y, rightPivot.z); - rlRotatef(45.0f * armWave0, 1, 0, 0); - DrawCubeTexture(playerTex, {0*PIXUNIT, -8*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 4, 20, 4, 4); - rlPopMatrix(); - - rlPopMatrix(); - - Vector3 dir = Vector3Subtract(camera.position, ent.position); - rlPushMatrix(); - rlTranslatef(ent.position.x, ent.position.y + 1.5f, ent.position.z); - rlRotatef(atan2f(dir.x, dir.z) * RAD2DEG, 0.0f, 1.0f, 0.0f); - rlRotatef(90.0f, 1.0f, 0.0f, 0.0f); - char name[12]; - sprintf(name, "Player %d", (int)ent.data[0]); - DrawText3D(fnt, name, {-MeasureTextEx(fnt, name, PIXUNIT * 4, 0).x * 1.5f, 0, 0}, PIXUNIT * 4, PIXUNIT, 1, true, WHITE); - rlPopMatrix(); } if(ent.type == 3) { DrawCube(pos_lerped, 1, 1, 1, RED); @@ -366,5 +231,4 @@ void DrawEntities(float dt) { DrawCubeBlock(terrain, pos_lerped, 1,1,1, BLOCKS[ent.data[1]]); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/helpers/inventory.cpp b/src/helpers/inventory.cpp index ec2ea33..62e8487 100644 --- a/src/helpers/inventory.cpp +++ b/src/helpers/inventory.cpp @@ -6,7 +6,7 @@ #include #include #include -#define PIXUNIT 1.0f / 16.0f + InventoryItem hotbar[ITEMS]; InventoryItem inventory[INVENTORY_SIZE]; static uint8_t selected = 0; diff --git a/src/helpers/menu.cpp b/src/helpers/menu.cpp index 7b5860c..9a6c304 100644 --- a/src/helpers/menu.cpp +++ b/src/helpers/menu.cpp @@ -29,7 +29,7 @@ static int MakeUIPOI(int x, int y) { std::unordered_set ui_pois; int TryConnect(const char* hostname); -//void InitSingleplayer(); +void InitSingleplayer(); void GameModeCleanup(); static int mouseX = -1; @@ -503,7 +503,7 @@ void DrawWorldSelect() { } if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48, 128, 0)) { UIResetMousePos(); - //InitSingleplayer(); + InitSingleplayer(); return; } if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48-48, 128, 0)) { @@ -550,12 +550,12 @@ void DrawMultiplayer() { EndDrawing(); UIHandleControls(); } - +void ExitSingleplayer(); void DrawPauseMenu() { UIBegin(); DrawRectangle(0,0,GetScreenWidth(),GetScreenHeight(),Fade(GRAY,0.5f)); if (Button(LocaleGet("exit").c_str(), GetScreenWidth()/2-64, 48, 128, 0)) { - GameModeCleanup(); + ExitSingleplayer(); UIResetMousePos(); return; } diff --git a/src/helpers/networking.cpp b/src/helpers/networking.cpp index 1dc646e..d62c00d 100644 --- a/src/helpers/networking.cpp +++ b/src/helpers/networking.cpp @@ -87,17 +87,17 @@ void BroadcastPacketR(ENetHost* server, void* data, int len) void SerializeFloat2Data(float v, void *target, int offset) { uint8_t *buf = (uint8_t*)target + offset; - if (!isfinite(v)) { // handle NaN/Inf as zero (choose policy) + if (!isfinite(v)) { buf[0] = 0; buf[1] = 0; return; } if (v < 0.0f) v = 0.0f; - if (v > 255.0f) v = 255.0f; // clamp to representable range + if (v > 255.0f) v = 255.0f; int intpart = (int)floorf(v); float frac = v - (float)intpart; - int frac_byte = (int)floorf(frac * 255.0f + 0.5f); // round to nearest + int frac_byte = (int)floorf(frac * 255.0f + 0.5f); if (frac_byte < 0) frac_byte = 0; if (frac_byte > 255) frac_byte = 255; buf[0] = (uint8_t)intpart; diff --git a/src/helpers/svlib.cpp b/src/helpers/svlib.cpp index e9a9ea8..a155a8a 100644 --- a/src/helpers/svlib.cpp +++ b/src/helpers/svlib.cpp @@ -11,6 +11,7 @@ #include static std::list players; +static std::list entities; static Chunk world[MAX_WORLD_AREA]; static ENetHost* server; @@ -167,6 +168,15 @@ static int PeerToPlayerID(ENetPeer* peer) { static bool CompareAddress(NetPlayer plr, ENetPeer* peer) { return plr.addr == peer->address.host && plr.port == (int)(peer->address.port); } + +static void SendPlayerSkin(ENetPeer* peer, NetPlayer plr) { + unsigned char responseD[plr.skin.size()+4]; + responseD[0] = NET_ARG_PLRSKIN; + responseD[1] = (plr.skin.size() & 0xFF00) << 8; + responseD[2] = plr.skin.size() & 0xFF; + memcpy(responseD+4, plr.skin.data(), plr.skin.size()); + SendPacketR(peer, responseD, plr.skin.size()+4); +} static void ParseData(ENetPacket* packet, ENetPeer* peer) { int len = packet->dataLength; unsigned char data[len]; @@ -237,8 +247,25 @@ static void ParseData(ENetPacket* packet, ENetPeer* peer) { responseP[1] = plr.id; responseP[8] = plr.yaw; SendPacketR(peer, responseP, 9); + SendPlayerSkin(peer, plr); } } + for (Entity &ent : entities) + { + unsigned char responseP[10+8]; + responseP[0] = NET_ARG_ENTITYSPAWN; + responseP[1] = ent.id & 0xFF00 >> 8; + responseP[2] = ent.id & 0xFF; + responseP[3] = ent.type; + SerializeFloat2Data(ent.position.x, responseP, 4); + SerializeFloat2Data(ent.position.y, responseP, 6); + SerializeFloat2Data(ent.position.z, responseP, 8); + for (int i = 0; i < 8; i++) + { + responseP[i+10] = ent.data_sv[i]; + } + SendPacketR(peer, responseP, 18); + } break; case NET_ARG_BLOCKDELTA: response[0] = NET_ARG_BLOCK; @@ -257,6 +284,30 @@ static void ParseData(ENetPacket* packet, ENetPeer* peer) { } } break; + case NET_ARG_PLRSKINSET: + { + NetPlayer tmp; + for (NetPlayer &plr : players) + { + if(plr.id == data[1]) { + int size = (data[2] << 8) | data[3]; + std::cout << size << std::endl; + for (int i = 0; i < size; i++) + { + plr.skin.push_back(data[4+i]); + } + tmp = plr; + break; + } + } + for (NetPlayer &plr : players) + { + if(!CompareAddress(plr, peer)) { + SendPlayerSkin(peer, tmp); + } + } + break; + } default: break; } @@ -290,11 +341,18 @@ void StartInternalServer(std::atomic_bool& started) { std::cout << "Serving on port: " << PORT << std::endl; serverStarted = true; started = true; + + Entity test = NewEntity(0); + test.type = 2; + test.position = {0, 64, 0}; + entities.push_back(test); } +void UpdateEntities(std::list entities, Chunk world[], float dt); void ServerNetworkUpdate() { if(serverStarted) { + UpdateEntities(entities, world, TPS_DIV); ENetEvent event; - while(enet_host_service (server, &event, 0) > 0) + while(enet_host_service (server, &event, 1000 / TPS) > 0) { switch (event.type) { @@ -308,6 +366,7 @@ void ServerNetworkUpdate() { id = FirstFreeID(players); response[1] = id; SendPacketR(event.peer, response, sizeof(response)); + { NetPlayer netPlayer; netPlayer.id = id; @@ -315,18 +374,18 @@ void ServerNetworkUpdate() { netPlayer.port = (int)(event.peer->address.port); netPlayer.peer = event.peer; players.push_back(netPlayer); - response[0] = NET_ARG_PLRCON; response[1] = netPlayer.id; BroadcastPacketR(server, response, sizeof(response)); } + CallPluginOnConnect(id); - break; + break; case ENET_EVENT_TYPE_RECEIVE: ParseData(event.packet, event.peer); enet_packet_destroy (event.packet); - break; + break; case ENET_EVENT_TYPE_DISCONNECT: printf ("%s disconnected.\n", event.peer -> data); @@ -346,8 +405,7 @@ void ServerNetworkUpdate() { break; } } - - break; + break; } } } diff --git a/src/helpers/vars.hpp b/src/helpers/vars.hpp index 98cbce1..4806e43 100644 --- a/src/helpers/vars.hpp +++ b/src/helpers/vars.hpp @@ -79,6 +79,10 @@ #define NET_ARG_PLRREG 0x07 // Same as ECHOMOVE, used as an answer to REQPLAYERS #define NET_ARG_ECHOYAW 0x08 // Byte 1 - ID, byte 2 - yaw #define NET_ARG_MESSAGEE 0x09 // Byte 1 - sender ID, byte 2 - length, rest is message (128b max) +#define NET_ARG_ENTITYSPAWN 0x0A // uint16_t entityWorldID, uint8_t entityTypeID, uint16_t x, uint16_t y, uint16_t z, uint8_t data[8] +#define NET_ARG_ENTITYMOVE 0x0B // uint16_t entityWorldID, uint16_t x, uint16_t y, uint16_t z +#define NET_ARG_PLRSKIN 0x0C // Byte 1 - ID, bytes 2-3 - size, rest is skin + //Client->Server // Byte 0 #define NET_ARG_PLAYERMOVE 0x80 // Byte 1-2 - player X, byte 3-4 - player Y, byte 5-6 - player Z, byte 7 - player yaw @@ -87,6 +91,7 @@ #define NET_ARG_REQPLAYERS 0x83 // No additional data #define NET_ARG_PLAYERYAW 0x84 // Byte 1 - yaw #define NET_ARG_MESSAGEC 0x85 // All is message (64b max) +#define NET_ARG_PLRSKINSET 0x86 // Byte 1 - ID, bytes 2-3 - size, rest is skin // //Errors #define NET_ERROR_DSCN 0x00 @@ -103,6 +108,7 @@ //Rendering #define RENDER_DISTANCE 16 #define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE +#define PIXUNIT 1.0f / 16.0f //Game stuff #define MAX_HP 100 @@ -225,17 +231,18 @@ struct Vector3I { int z; }; struct Entity { + uint16_t id; uint8_t type; - uint8_t id; uint8_t damage_flash; - uint8_t data[16]; + uint8_t data[4]; + uint8_t data_sv[8]; + bool free; float smoothing; float health; float lifetime; Vector3 position; Vector3 velocity; unsigned short yaw; - bool free; }; struct NetPlayer @@ -248,6 +255,9 @@ struct NetPlayer float x; float y; float z; + std::string nickname; + Texture2D texture; + std::vector skin; }; struct MemInfo { diff --git a/src/rcraft.cpp b/src/rcraft.cpp index cf49842..3c45733 100644 --- a/src/rcraft.cpp +++ b/src/rcraft.cpp @@ -15,8 +15,11 @@ #include #include #include -#include #include +#include +#include +#include +#include #define MAX_RAY_DISTANCE 8.0f struct MessageData { std::string message; @@ -32,11 +35,14 @@ Vector2 cameraMovementSmooth; static float camYaw = 0.0f; static float camPitch = -45.0f; static const float acceleration = 48.0f; -static const float drag = 6.0f; // tuned for feel +static const float drag = 6.0f; +static bool singleplayerServer; Camera camera; +Texture2D playerTex; bool online = false; bool flying = false; +void DrawEntities(std::list entities, float dt); unsigned long long worldTime; static float entUpdateCounter; @@ -53,7 +59,6 @@ Font fnt; Texture2D terrain; Texture2D water; Texture2D white_pixel; -Entity* ent; const bool ROTATE_PLAYER_WITH_CAMERA = true; static Sound wood_place; static Sound stone_place; @@ -63,9 +68,10 @@ bool tick_entities; const std::string LocaleGet(std::string loc); bool InputGetKeyDown(const std::string name); bool InputGetKeyPressed(const std::string name); -extern std::list entities; std::bitset clouds; std::queue tickedBlocks; +static std::list entities; +static std::map players; struct MeshUnit { Model model; int vertices; @@ -91,6 +97,96 @@ static Vector3 CameraForwardFromYawPitch(float yaw, float pitch) f.z = cosf(pitch) * sinf(yaw); return Vector3Normalize(f); } +static const char* GetPlayerTexturePath() { + if(FileExists(PathifyUser("player.png"))) { + return PathifyUser("player.png"); + } + else { + return Pathify("nekit.png"); + } +} +static void DrawPlayer(Texture2D texture, NetPlayer netPlayer) { + Color color = WHITE; + float x = netPlayer.x; + float y = netPlayer.y; + float z = netPlayer.z; + int _yaw = netPlayer.yaw; + Vector3 posLerp = Vector3Add((Vector3){x, y, z}, {-0.5f, -0.1f, -0.5f}); + + float time = GetTime() * 4.0f; + float armWave0 = sinf(time * PI); + float armWave1 = -abs(cosf(time * PI)); + float headWave = cosf(time * PI); + posLerp = Vector3Add(posLerp, {0, abs(sinf(time * PI)) * 0.1f, 0}); + Vector3 headPivot = Vector3Add(posLerp, (Vector3){0, 16*PIXUNIT, 0}); + float yaw = -yaw / 65535.0f * 360.0f - 90; + Texture2D tex = netPlayer.texture; + rlPushMatrix(); + rlTranslatef(posLerp.x, posLerp.y, posLerp.z); + rlRotatef(yaw, 0, 1, 0); + rlTranslatef(-posLerp.x, -posLerp.y, -posLerp.z); + + // + + rlPushMatrix(); + rlTranslatef(headPivot.x, headPivot.y, headPivot.z); + rlRotatef(25.0f * armWave0, 1, 0, 0); + rlRotatef(25.0f * headWave, 0, 0, 1); + // Head + DrawCubeTexture(tex, {0, 4*PIXUNIT, 0}, 8*PIXUNIT, 8*PIXUNIT, 8*PIXUNIT, WHITE, 8, 8, 8, 8); + rlPopMatrix(); + + Vector3 leftPivot = Vector3Add(posLerp, (Vector3){-6*PIXUNIT, 1.25f - 5*PIXUNIT, 0}); + Vector3 rightPivot = Vector3Add(posLerp, (Vector3){6*PIXUNIT, 1.25f - 5*PIXUNIT, 0}); + + rlPushMatrix(); + rlTranslatef(leftPivot.x, leftPivot.y, leftPivot.z); + rlRotatef(45.0f * armWave0, 1, 0, 0); + rlRotatef(45.0f * armWave1, 0, 0, 1); + DrawCubeTexture(tex, (Vector3){0, -6*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4); + rlPopMatrix(); + + rlPushMatrix(); + rlTranslatef(rightPivot.x, rightPivot.y, rightPivot.z); + rlRotatef(-45.0f * armWave0, 1, 0, 0); + rlRotatef(-45.0f * armWave1, 0, 0, 1); + DrawCubeTexture(tex, (Vector3){0, -6*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4); + rlPopMatrix(); + + Vector3 body = Vector3Add(posLerp, {0, 1.25f - 10*PIXUNIT, 0}); + + rlPushMatrix(); + rlTranslatef(body.x, body.y, body.z); + DrawCubeTexture(tex, Vector3Zero(), 8*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 20, 20, 8, 4); + rlPopMatrix(); + + leftPivot = Vector3Add(posLerp, (Vector3){-2*PIXUNIT, 1.25f - 14*PIXUNIT, 0}); + rightPivot = Vector3Add(posLerp, (Vector3){2*PIXUNIT, 1.25f - 14*PIXUNIT, 0}); + + rlPushMatrix(); + rlTranslatef(leftPivot.x, leftPivot.y, leftPivot.z); + rlRotatef(-45.0f * armWave0, 1, 0, 0); + DrawCubeTexture(tex, {0*PIXUNIT, -8*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 4, 20, 4, 4); + rlPopMatrix(); + + rlPushMatrix(); + rlTranslatef(rightPivot.x, rightPivot.y, rightPivot.z); + rlRotatef(45.0f * armWave0, 1, 0, 0); + DrawCubeTexture(tex, {0*PIXUNIT, -8*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 4, 20, 4, 4); + rlPopMatrix(); + + rlPopMatrix(); + + Vector3 dir = Vector3Subtract(camera.position, (Vector3){x, y, z}); + + rlPushMatrix(); + rlTranslatef(x, y + 1.5f, z); + rlRotatef(atan2f(dir.x, dir.z) * RAD2DEG, 0.0f, 1.0f, 0.0f); + rlRotatef(90.0f, 1.0f, 0.0f, 0.0f); + const char* name = netPlayer.nickname.c_str(); + DrawText3D(fnt, name, {-MeasureTextEx(fnt, name, PIXUNIT * 4, 0).x * 1.5f, 0, 0}, PIXUNIT * 4, PIXUNIT, 1, true, WHITE); + rlPopMatrix(); +} Chunk world[MAX_WORLD_AREA]; static MeshUnit rendering[MAX_WORLD_AREA]; static MeshUnit renderingT[MAX_WORLD_AREA]; @@ -234,17 +330,14 @@ static void ResolveCollisions(float dt) if (ix > 0 && iy > 0 && iz > 0) { - // find smallest penetration axis and push out along it if (ix < iy && ix < iz) { - // push on X if (player_position.x < bx0) player_position.x -= ix; else player_position.x += ix; player_velocity.x = 0; } else if (iy < ix && iy < iz) { - // push on Y if (player_position.y < by0) player_position.y -= iy; else player_position.y += iy; if (player_velocity.y > 0) player_velocity.y = 0; @@ -252,7 +345,6 @@ static void ResolveCollisions(float dt) } else { - // push on Z if (player_position.z < bz0) player_position.z -= iz; else player_position.z += iz; player_velocity.z = 0; @@ -357,21 +449,12 @@ static inline void RemeshChunkForBlock(int bx, int by, int bz) if (cx >= 0 && cx < MAX_WORLD_SIZE && cz >= 0 && cz < MAX_WORLD_SIZE) RemeshChunk(cx, cz); } -static void AddNekit() { - Entity temp = NewEntity(); - temp.type = 2; - temp.health = 50; - temp.velocity = {0, 0, 0}; - temp.position = player_position + (Vector3){0, 10, 0}; - AddEntity(temp); -} - ENetPeer *peer; ENetHost* client; static std::stack> worldPacketStack; static int fetchedChunks; -int plrId = -1; +int plrId = 0; static bool pauseMenuActive; void _LoadWorld(const char* path) { @@ -451,7 +534,7 @@ void SetBlockNetwork(Chunk world[], int bx, int by, int bz, int t) { data[2] = (uint8_t)by; data[3] = (uint8_t)bz; data[4] = (uint8_t)t; - SendPacketR(peer, data, sizeof(data)); + SendPacketR(peer, data, 5); } else { SetBlock(world, bx, by, bz, t); @@ -507,14 +590,16 @@ int TryConnect(const char* hostname) { "No available peers for initiating an ENet connection.\n"); return NET_ERROR_NOTFOUND; } - - if (enet_host_service (client, & event, 5000) > 0 && - event.type == ENET_EVENT_TYPE_CONNECT) + printf("Found a host\n"); + while (!serverStarted) { + if(!online) serverStarted = true; + } + if (enet_host_service (client, & event, 10000) && event.type == ENET_EVENT_TYPE_CONNECT){ puts ("Connection succeeded."); char data[1]; data[0] = NET_ARG_REQWORLD; - SendPacketR(peer, data, 1); + SendPacketR(peer, data, 1); // Tell the server to send all chunks online = true; state = GAME_STATE_LOADING; return 0; @@ -528,26 +613,37 @@ int TryConnect(const char* hostname) { return -1; } -//std::thread serverThread; + + +std::thread serverThread; std::atomic_bool stop_server = false; + void StartInternalServer(std::atomic_bool& started); -/*void ServerThread(std::atomic_bool& started) { +void ServerThread(std::atomic_bool& started) { StartInternalServer(started); stop_server = false; while(true) { - if (stop_server) + if (stop_server) { + serverStarted = false; + StopInternalServer(); return; + } ServerNetworkUpdate(); } -}*/ -/*void InitSingleplayer() { +} +void InitSingleplayer() { online = true; serverThread = std::thread(ServerThread, std::ref(serverStarted)); int result = TryConnect("localhost"); if(result == NET_ERROR_FAILED) { state = GAME_STATE_MAINMENU; + return; } -}*/ + singleplayerServer = true; +} +void ExitSingleplayer() { + GameModeCleanup(); +} std::vector messages; bool survival = false; bool chatOpen = false; @@ -695,19 +791,6 @@ static void GameUpdate(Camera camera, float &time) { Vector3 rayOrigin = (Vector3){ player_position.x, player_position.y + 1.7f, player_position.z};; Vector3 hitBlock, prevBlock; - if(IsKeyDown(KEY_N) && !online) { - AddNekit(); - } - if(IsKeyPressed(KEY_F10)) { - tick_entities = !tick_entities; - } - if(IsKeyPressed(KEY_B) && !online) { - Entity temp = NewEntity(); - temp.type = 3; - temp.position = camera.position; - temp.velocity = (camera.target - camera.position) * 4.0f; - AddEntity(temp); - } if (RaycastBlock(rayOrigin, Vector3Normalize(camForward), 5, &hitBlock, &prevBlock)) { if((int)hitBlock.x != (int)highlightBlock.x || (int)hitBlock.y != (int)highlightBlock.y || (int)hitBlock.z != (int)highlightBlock.z) @@ -894,22 +977,6 @@ static void GameUpdate(Camera camera, float &time) { dirtyChunks[bestIdx] = false; } AddProfilerPart("rebuild", GetTime()-PROFCOUNT, BLUE); - - - PROFCOUNT = GetTime(); - if(tick_entities) { - entUpdateCounter += dt; - if(entUpdateCounter > TPS_DIV) { - while (entUpdateCounter > 0) - { - UpdateEntities(world, TPS_DIV / 2.0f); - entUpdateCounter-= TPS_DIV; - } - TickAvailableBlocks(); - entUpdateCounter = 0.0f; - } - } - AddProfilerPart("entities", GetTime()-PROFCOUNT, MAGENTA); PROFCOUNT = GetTime(); ParticlesUpdate(dt, world); @@ -932,7 +999,7 @@ static void GameUpdate(Camera camera, float &time) { Frustum frustum = ExtractFrustumPlanes(camera, (float)GetScreenWidth() / (float)GetScreenHeight()); BeginDrawing(); ClearBackground(RAYWHITE); - DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLUE); + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), {120, 167, 255}); BeginMode3D(camera); @@ -952,7 +1019,10 @@ static void GameUpdate(Camera camera, float &time) { } AddProfilerPart("chunk render opq", GetTime()-PROFCOUNT, MAROON); - DrawEntities(dt); + DrawEntities(entities, 0); + for (const auto& [id, netplayer] : players) { + DrawPlayer(terrain, netplayer); + } ParticlesDraw(); //Transparent shit rlDisableDepthMask(); @@ -1126,13 +1196,6 @@ static void GameUpdate(Camera camera, float &time) { DrawTriangle({x3, y3}, {x2, y2}, {x1, y1}, p.color); angleA = angleB; } - /*float mid = (startAngle + endAngle) * 0.5f; - float lx = cx + cosf(mid) * (radius * 0.6f); - float ly = cy + sinf(mid) * (radius * 0.6f); - char label[128]; - sprintf(label, "%s (%.1f ms)", p.id.c_str(), p.time * 1000.0f); - DrawText(label, lx - 20, ly - 6, 10, WHITE);*/ - startAngle = endAngle; } int T = 0; @@ -1157,10 +1220,12 @@ static void GameUpdate(Camera camera, float &time) { if(msg != nullptr) { chatOpen = false; DisableCursor(); - char data[1+MAX_MESSAGE_LENGTH]; - data[0] = NET_ARG_MESSAGEC; - memcpy(data+1, msg, MAX_MESSAGE_LENGTH); - SendPacketR(peer, data, 1+MAX_MESSAGE_LENGTH); + if(online) { + char data[1+MAX_MESSAGE_LENGTH]; + data[0] = NET_ARG_MESSAGEC; + memcpy(data+1, msg, MAX_MESSAGE_LENGTH); + SendPacketR(peer, data, 1+MAX_MESSAGE_LENGTH); + } memset(msg, 0, MAX_MESSAGE_LENGTH); } } @@ -1187,9 +1252,30 @@ static void GameStart() { } LoadPlayerData(); //PlayRandomMusic(); - char data[1]; - data[0] = NET_ARG_REQPLAYERS; - SendPacketR(peer, data, 1); + if(online) { + char data[1]; + data[0] = NET_ARG_REQPLAYERS; + SendPacketR(peer, data, 1); + + int memory_size = 65535; + char* dynamic_buffer = new char[memory_size]; + + std::ifstream file; + file.open(GetPlayerTexturePath(), std::ios_base::in | std::ios_base::binary ); + file.read(dynamic_buffer, memory_size); + int bytes_read = (int)(file.gcount()); + std::cout << bytes_read << std::endl; + file.close(); + uint8_t skin_packet[4+bytes_read]; + skin_packet[0] = NET_ARG_PLRSKINSET; + skin_packet[1] = plrId; + skin_packet[2] = (bytes_read & 0xFF00) >> 8; + skin_packet[3] = bytes_read & 0xFF; + memcpy(skin_packet+4, dynamic_buffer, bytes_read); + SendPacketR(peer, skin_packet, sizeof(skin_packet)*sizeof(uint8_t)); + //free(skin_packet); + //free(dynamic_buffer); + } camera = { 0 }; camera.position = (Vector3){ MAX_WORLD_SIZE / 2 * CHUNK_SIZE, 12.0f, MAX_WORLD_SIZE / 2 * CHUNK_SIZE}; @@ -1213,22 +1299,8 @@ static void GameStart() { grass_place = LoadSound(Pathify("sound/block_grass.wav")); } -static void CreateNetPlayer(int id) { - Entity temp = NewEntity(); - temp.type = 1; - temp.position = player_position; - temp.data[0] = id; - temp.data[1] = 0; - AddEntity(temp); -} static void RemovePlayerEntity(int id) { - auto match = [&](const Entity ent){ - return ent.data[0] == id && ent.type == 1; - }; - auto it = std::find_if(entities.begin(), entities.end(), match); - if (it != entities.end()) { - entities.erase(it); - } + players.erase(id); } static void ParseMessagePacket(std::vector &a_data) { std::string output; @@ -1243,6 +1315,14 @@ static void ParseMessagePacket(std::vector &a_data) { msg.message = output; messages.push_back(msg); } +static void CreatePlayer(int id) { + if(id != plrId) { + NetPlayer temp = {0}; + temp.id = id; + temp.nickname = "testificate"; + players[id] = temp; + } +} static void ParseData(ENetPacket* packet) { int len = packet->dataLength; std::vector a_data; @@ -1251,6 +1331,7 @@ static void ParseData(ENetPacket* packet) { { a_data.push_back(packet->data[i]); } + switch (a_data[0]) { case NET_ARG_CHUNKF: @@ -1263,9 +1344,7 @@ static void ParseData(ENetPacket* packet) { break; case NET_ARG_PLRCON: puts("Player connected"); - if(a_data[1] != plrId) { - CreateNetPlayer(a_data[1]); - } + CreatePlayer(a_data[1]); break; case NET_ARG_PLRDCN: puts("Player disconnected"); @@ -1281,49 +1360,37 @@ static void ParseData(ENetPacket* packet) { player_position.y = y; player_position.z = z; } - for (Entity &plr : entities) - { - std::cout << (int)(plr.data[0]) << " " << (int)(plr.type) << std::endl; - if(plr.data[0] == a_data[1] && plr.type == 1) { - float x = DeserializeFloat(a_data[2],a_data[3]); - float y = DeserializeFloat(a_data[4],a_data[5]); - float z = DeserializeFloat(a_data[6],a_data[7]); - plr.position.x = x; - plr.position.y = y; - plr.position.z = z; - //plr.yaw = (short)floorf(a_data[8] / 255.0f* 65536); - plr.data[1] = 255; - std::cout << x << " " << y << " " << z << " " << (float)(plr.yaw) << std::endl; - } + else { + NetPlayer &plr = players[a_data[1]]; + players[plrId].yaw = a_data[2]; + float x = DeserializeFloat(a_data[2],a_data[3]); + float y = DeserializeFloat(a_data[4],a_data[5]); + float z = DeserializeFloat(a_data[6],a_data[7]); + plr.x = x; + plr.y = y; + plr.z = z; } break; case NET_ARG_ECHOYAW: std::cout << "Server requested to sync yaw " << (int)(a_data[1]) << std::endl; - for (Entity &plr : entities) - { - if(plr.data[0] == a_data[1] && plr.type == 1) { - plr.yaw = (short)floorf(a_data[2] / 255.0f * 65536); - } + if(a_data[1] != plrId) { + NetPlayer &plr = players[a_data[1]]; + players[plrId].yaw = a_data[2]; } break; case NET_ARG_PLRREG: puts("Got a connected player"); if(a_data[1] != plrId) { - CreateNetPlayer(a_data[1]); + CreatePlayer(a_data[1]); + NetPlayer &plr = players[a_data[1]]; + float x = DeserializeFloat(a_data[2],a_data[3]); + float y = DeserializeFloat(a_data[4],a_data[5]); + float z = DeserializeFloat(a_data[6],a_data[7]); + plr.x = x; + plr.y = y; + plr.z = z; + plr.yaw = (short)floorf(a_data[8] / 255.0f * 65536); } - for (Entity &plr : entities) - { - if(plr.data[0] == a_data[1] && plr.type == 1) { - float x = DeserializeFloat(a_data[2],a_data[3]); - float y = DeserializeFloat(a_data[4],a_data[5]); - float z = DeserializeFloat(a_data[6],a_data[7]); - plr.position.x = x; - plr.position.y = y; - plr.position.z = z; - plr.yaw = (short)floorf(a_data[8] / 255.0f * 65536); - } - } - break; case NET_ARG_BLOCK: SetBlock(world, a_data[2], a_data[3], a_data[4], a_data[5]); dirtyChunks[GetIndexWorld(a_data[2] / 16, a_data[4] / 16)] = true; @@ -1343,6 +1410,32 @@ static void ParseData(ENetPacket* packet) { case NET_ARG_MESSAGEE: ParseMessagePacket(a_data); break; + case NET_ARG_ENTITYSPAWN: + { + Entity ent = {0}; + ent.id = a_data[1] << 8 | a_data[2]; + ent.type = a_data[3]; + float x = DeserializeFloat(a_data[4],a_data[5]); + float y = DeserializeFloat(a_data[6],a_data[7]); + float z = DeserializeFloat(a_data[8],a_data[9]); + memcpy(ent.data_sv, a_data.data()+10, 8); + entities.push_back(ent); + } + break; + case NET_ARG_PLRSKIN: + { + NetPlayer &plr = players[a_data[1]]; + int texsize = (a_data[2] << 8) | a_data[3]; + uint8_t img[texsize]; + std::cout << texsize << std::endl; + memcpy(img, a_data.data()+4, texsize); + Image temp = LoadImageFromMemory(".png", img, texsize); + plr.texture = LoadTextureFromImage(temp); + std::cout << plr.id << std::endl; + UnloadImage(temp); + //free(img); + } + break; default: puts("Malformed data?"); break; @@ -1403,14 +1496,10 @@ void NetworkUpdate() { void GameModeCleanupFull() { if(online) { - enet_host_destroy(client); online = false; } - - stop_server = true; - //serverThread.join(); - + for (int idx = 0; idx < MAX_WORLD_AREA; idx++) { if(loadedChunks[idx]) { @@ -1418,6 +1507,7 @@ void GameModeCleanupFull() { //UnloadModel(rendering[idx]); } } + stop_server = true; memset(loadedChunks, 0, sizeof(loadedChunks)); memset(dirtyChunks, 0, sizeof(dirtyChunks)); entities.clear(); @@ -1430,7 +1520,6 @@ void GameModeCleanup() { pauseMenuActive = false; EnableCursor(); GameModeCleanupFull(); - state = GAME_STATE_MAINMENU; worldCreationProgress = 0; worldCreationStep = 0; } @@ -1439,7 +1528,6 @@ extern void InitMenu(); int main(void) { SetTraceLogLevel(LOG_WARNING); - NetworkingStart(); SetConfigFlags(FLAG_WINDOW_RESIZABLE); InitWindow(WIDTH, HEIGHT, GAME_NAME); InitWorldgen(0); @@ -1450,6 +1538,8 @@ int main(void) LocaleUpdate(); LoadRecipes(); + playerTex = LoadTexture(GetPlayerTexturePath()); + camera = { 0 }; camera.position = (Vector3){0, 0, 0}; camera.target = (Vector3){camera.position.x, camera.position.y, camera.position.z + 1}; @@ -1496,7 +1586,6 @@ int main(void) GetXZFromIndex(idx, &x, &z); c.x = (uint8_t)x; c.z = (uint8_t)z; - std::cout << data.size() << std::endl; for (int i = 2; i < CHUNK_DATA_SIZE+2; i++) { c.blocks[i-2] = data[i]; @@ -1564,12 +1653,14 @@ int main(void) } if (worldCreationStep == 2) { - //RebuildOpaqueMask(&world[idx]); + RebuildOpaqueMask(&world[idx]); } if (worldCreationStep == 3) { dirtyChunks[idx] = true; } - if(online) + if(!(worldCreationStep == 0 && online)) + worldCreationProgress++; + else worldCreationProgress = fetchedChunks+1; } } @@ -1595,7 +1686,15 @@ int main(void) DrawMultiplayer(); break; case GAME_STATE_TRANSITION: + DrawBackground(); DrawLogoCenter(); + if(!singleplayerServer || !serverStarted) { + state = GAME_STATE_MAINMENU; + } + if (serverThread.joinable()) { + serverThread.join(); + singleplayerServer = false; + } break; case GAME_STATE_OPTIONS: DrawControls(); @@ -1603,7 +1702,7 @@ int main(void) } } - enet_deinitialize(); + GameModeCleanupFull(); UnloadTexture(terrain);