R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
ServerGameBindings.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** RTYPE
4** File description:
5** ServerGameBindings implementation
6*/
7
9#include <cstdlib>
10#include <ctime>
24
25namespace scripting::bindings {
26
27 void bindServerGame(sol::state &lua, ecs::wrapper::ECSWorld *world, LuaEngine *engine) {
28 if (!world) {
29 LOG_ERROR("Cannot bind server game functions: world is null");
30 return;
31 }
32 if (!engine) {
33 LOG_ERROR("Cannot bind server game functions: engine is null");
34 return;
35 }
36
37 // Seed random number generator (do this once)
38 static bool seeded = false;
39 if (!seeded) {
40 std::srand(static_cast<unsigned int>(std::time(nullptr)));
41 seeded = true;
42 }
43
44 // Spawn a basic enemy at position
45 lua.set_function("spawnEnemy",
46 [world](float x, float y, const std::string &enemyType) -> ecs::wrapper::Entity {
47 try {
48 auto entity = world->createEntity();
49
50 entity.with(ecs::Transform(x, y));
51 entity.with(ecs::Velocity(-1.0f, 0.0f, 100.0f)); // Move left
52 entity.with(ecs::Health(100, 100));
53
54 LOG_INFO("[LUA] Spawned enemy '" + enemyType + "' at (" + std::to_string(x) +
55 ", " + std::to_string(y) + ")");
56
57 return entity;
58 } catch (const std::exception &e) {
59 LOG_ERROR("[LUA] Failed to spawn enemy: " + std::string(e.what()));
60 throw;
61 }
62 });
63
64 // Spawn a projectile
65 lua.set_function(
66 "spawnProjectile",
67 [world](float x, float y, float dirX, float dirY, float speed) -> ecs::wrapper::Entity {
68 try {
69 auto entity = world->createEntity();
70
71 entity.with(ecs::Transform(x, y));
72 entity.with(ecs::Velocity(dirX, dirY, speed));
73
74 LOG_DEBUG("[LUA] Spawned projectile at (" + std::to_string(x) + ", " + std::to_string(y) +
75 ")");
76
77 return entity;
78 } catch (const std::exception &e) {
79 LOG_ERROR("[LUA] Failed to spawn projectile: " + std::string(e.what()));
80 throw;
81 }
82 });
83
84 // Get current time (useful for timing/animations)
85 lua.set_function("getTime", []() -> float {
86 return static_cast<float>(std::clock()) / static_cast<float>(CLOCKS_PER_SEC);
87 });
88
89 // Math helpers
90 lua.set_function("distance", [](float x1, float y1, float x2, float y2) -> float {
91 float dx = x2 - x1;
92 float dy = y2 - y1;
93 return std::sqrt(dx * dx + dy * dy);
94 });
95
96 lua.set_function("normalize", [&lua](float x, float y) -> sol::table {
97 float length = std::sqrt(x * x + y * y);
98 if (length == 0.0f)
99 length = 1.0f;
100
101 sol::state_view lua_view(lua.lua_state());
102 sol::table result = lua_view.create_table();
103 result["x"] = x / length;
104 result["y"] = y / length;
105 return result;
106 });
107
108 // Spawn power-up (temporary buff)
109 lua.set_function(
110 "spawnPowerUp",
111 [world](const std::string &buffType, float duration, float value, float x,
112 float y) -> ecs::wrapper::Entity {
113 try {
115
116 // Convert string to BuffType
117 if (buffType == "speed")
119 else if (buffType == "damage")
121 else if (buffType == "firerate")
123 else if (buffType == "shield")
125 else if (buffType == "regen")
127
128 auto entity = world->createEntity();
129 entity.with(ecs::Transform(x, y));
130 entity.with(ecs::Collectible(type, duration, value));
131 entity.with(ecs::Collider(20.0f, 20.0f, 0.0f, 0.0f, 8, 0xFFFFFFFF, false));
132 entity.with(ecs::Sprite("powerup.png", {0, 0, 20, 20}, 1.0f, 0.0f, false, false, 0));
133
134 LOG_INFO("[LUA] Spawned power-up '" + buffType + "' at (" + std::to_string(x) + ", " +
135 std::to_string(y) + ")");
136
137 return entity;
138 } catch (const std::exception &e) {
139 LOG_ERROR("[LUA] Failed to spawn power-up: " + std::string(e.what()));
140 throw;
141 }
142 });
143
144 // Spawn permanent upgrade
145 lua.set_function(
146 "spawnUpgrade",
147 [world](const std::string &buffType, float value, float x, float y) -> ecs::wrapper::Entity {
148 try {
149 ecs::BuffType type = ecs::BuffType::MultiShot; // Default
150
151 // Convert string to BuffType
152 if (buffType == "multishot")
154 else if (buffType == "doubleshot")
156 else if (buffType == "tripleshot")
158 else if (buffType == "piercing")
160 else if (buffType == "homing")
162 else if (buffType == "maxhealth")
164
165 auto entity = world->createEntity();
166 entity.with(ecs::Transform(x, y));
167 entity.with(ecs::Collectible(type, 0.0f, value)); // 0.0f = permanent
168 entity.with(ecs::Collider(20.0f, 20.0f, 0.0f, 0.0f, 8, 0xFFFFFFFF, false));
169 entity.with(ecs::Sprite("upgrade.png", {0, 0, 20, 20}, 1.0f, 0.0f, false, false, 0));
170
171 LOG_INFO("[LUA] Spawned upgrade '" + buffType + "' at (" + std::to_string(x) + ", " +
172 std::to_string(y) + ")");
173
174 return entity;
175 } catch (const std::exception &e) {
176 LOG_ERROR("[LUA] Failed to spawn upgrade: " + std::string(e.what()));
177 throw;
178 }
179 });
180
181 // Spawn health pack
182 lua.set_function(
183 "spawnHealthPack", [world](int healthRestore, float x, float y) -> ecs::wrapper::Entity {
184 try {
185 auto entity = world->createEntity();
186 entity.with(ecs::Transform(x, y));
187 entity.with(ecs::Collectible(healthRestore));
188 entity.with(ecs::Collider(20.0f, 20.0f, 0.0f, 0.0f, 8, 0xFFFFFFFF, false));
189 entity.with(ecs::Sprite("health.png", {0, 0, 20, 20}, 1.0f, 0.0f, false, false, 0));
190
191 LOG_INFO("[LUA] Spawned health pack at (" + std::to_string(x) + ", " + std::to_string(y) +
192 ")");
193
194 return entity;
195 } catch (const std::exception &e) {
196 LOG_ERROR("[LUA] Failed to spawn health pack: " + std::string(e.what()));
197 throw;
198 }
199 });
200
201 // Spawn wall/obstacle
202 lua.set_function(
203 "spawnWall",
204 [world](float x, float y, float width, float height, sol::optional<bool> destructible,
205 sol::optional<int> health) -> ecs::wrapper::Entity {
206 try {
207 bool isDestructible = destructible.value_or(false);
208 int wallHealth = health.value_or(0);
209
210 auto entity = world->createEntity();
211 entity.with(ecs::Transform(x, y));
212 entity.with(ecs::Wall(isDestructible));
213 entity.with(ecs::Collider(width, height, 0.0f, 0.0f, 16, 0xFFFFFFFF, false));
214 entity.with(ecs::Sprite("Wall.png",
215 {0, 0, static_cast<int>(width), static_cast<int>(height)}, 1.0f,
216 0.0f, false, false, 0));
217
218 if (isDestructible && wallHealth > 0) {
219 entity.with(ecs::Health(wallHealth, wallHealth));
220 }
221
222 LOG_INFO("[LUA] Spawned wall at (", x, ", ", y, ") - Size: ", width, "x", height,
223 isDestructible ? " [Destructible]" : " [Solid]");
224
225 return entity;
226 } catch (const std::exception &e) {
227 LOG_ERROR("[LUA] Failed to spawn wall: ", e.what());
228 throw;
229 }
230 });
231
232 // Queue a spawn request through a Spawner entity
233 // Usage: queueSpawn(spawnerEntity, x, y, type, scriptPath, health, scoreValue)
234 lua.set_function("queueSpawn", [world](ecs::wrapper::Entity spawner, float x, float y,
235 const std::string &enemyType, const std::string &scriptPath,
236 float health, int scoreValue) {
237 try {
238 if (!world) {
239 LOG_ERROR("[LUA] queueSpawn: world is null");
240 return;
241 }
242
243 if (!spawner.isValid()) {
244 LOG_WARNING("[LUA] Cannot queue spawn: invalid spawner entity (address: ",
245 spawner.getAddress(), ")");
246 return;
247 }
248
249 if (!spawner.has<ecs::Spawner>()) {
250 LOG_WARNING("[LUA] Entity (", spawner.getAddress(), ") does not have Spawner component");
251 return;
252 }
253
254 ecs::Spawner &spawnerComp = spawner.get<ecs::Spawner>();
255 ecs::SpawnRequest request{x, y, enemyType, scriptPath, health, scoreValue, 0.0f};
256 spawnerComp.queueSpawn(request);
257
258 LOG_DEBUG("[LUA] Queued spawn for ", enemyType, " at (", x, ", ", y, ")");
259 } catch (const std::exception &e) {
260 LOG_ERROR("[LUA] queueSpawn exception: ", e.what());
261 }
262 });
263
264 lua.set_function("setSpawnerConfig", [world](ecs::wrapper::Entity spawner, sol::table configTable) {
265 try {
266 if (!world) {
267 LOG_ERROR("[LUA] setSpawnerConfig: world is null");
268 return;
269 }
270
271 if (!spawner.isValid()) {
272 LOG_WARNING("[LUA] Cannot set spawner config: invalid spawner entity (address: ",
273 spawner.getAddress(), ")");
274 return;
275 }
276
277 if (!spawner.has<ecs::Spawner>()) {
278 LOG_WARNING("[LUA] Entity (", spawner.getAddress(), ") does not have Spawner component");
279 return;
280 }
281
282 ecs::Spawner &spawnerComp = spawner.get<ecs::Spawner>();
283 ecs::SpawnerConfig config;
284
285 // Parse waves
286 sol::optional<sol::table> wavesTableOpt = configTable["waves"];
287 if (wavesTableOpt) {
288 sol::table wavesTable = wavesTableOpt.value();
289 for (auto &wavePair : wavesTable) {
290 sol::table waveTable = wavePair.second;
291 ecs::WaveConfig waveConfig;
292
293 // Parse enemies in wave (using enemyConfigs key from Lua)
294 sol::optional<sol::table> enemiesTableOpt = waveTable["enemyConfigs"];
295 if (!enemiesTableOpt) {
296 sol::optional<sol::table> enemiesTableOpt = waveTable["enemies"];
297 }
298 if (enemiesTableOpt) {
299 sol::table enemiesTable = enemiesTableOpt.value();
300 for (auto &enemyPair : enemiesTable) {
301 sol::table enemyTable = enemyPair.second;
302 ecs::SpawnRequest request;
303 request.x = enemyTable.get_or("x", 0.0f);
304 request.y = enemyTable.get_or("y", 0.0f);
305 request.enemyType = enemyTable.get_or<std::string>("type", "basic");
306 request.scriptPath = enemyTable.get_or<std::string>("script", "");
307 request.health = enemyTable.get_or("health", 100.0f);
308 request.scoreValue = enemyTable.get_or("scoreValue", 100);
309 request.spawnDelay = enemyTable.get_or("delay", 0.0f);
310 request.hasSpawned = false;
311 waveConfig.enemies.push_back(request);
312 }
313 }
314
315 waveConfig.spawnInterval = waveTable.get_or("spawnInterval", 1.0f);
316 config.waves.push_back(waveConfig);
317 }
318 }
319
320 // Parse wave intervals
321 sol::optional<sol::table> intervalsTableOpt = configTable["wavesIntervals"];
322 if (intervalsTableOpt) {
323 sol::table intervalsTable = intervalsTableOpt.value();
324 for (auto &intervalPair : intervalsTable) {
325 int interval = intervalPair.second.as<int>();
326 config.wavesIntervals.push_back(interval);
327 }
328 }
329
330 spawnerComp.setConfig(config);
331
332 LOG_INFO("[LUA] Set spawner config for entity ", spawner.getAddress(), " with ",
333 config.waves.size(), " waves");
334 } catch (const std::exception &e) {
335 LOG_ERROR("[LUA] setSpawnerConfig exception: ", e.what());
336 }
337 });
338
339 LOG_INFO("Server game bindings initialized");
340 }
341
342} // namespace scripting::bindings
#define LOG_INFO(...)
Definition Logger.hpp:181
#define LOG_DEBUG(...)
Definition Logger.hpp:180
#define LOG_ERROR(...)
Definition Logger.hpp:183
#define LOG_WARNING(...)
Definition Logger.hpp:182
Component for items that can be picked up by players.
Component for collision detection and physics interactions.
Definition Collider.hpp:21
Component representing entity health and invincibility.
Definition Health.hpp:20
Component that holds spawn requests to be processed by SpawnSystem.
Definition Spawner.hpp:48
void queueSpawn(const SpawnRequest &request)
Queue a spawn request.
Definition Spawner.hpp:57
void setConfig(const SpawnerConfig &config)
Definition Spawner.hpp:82
Component representing a visual sprite from a texture.
Definition Sprite.hpp:32
Component representing position, rotation and scale in 2D space.
Definition Transform.hpp:20
Component representing movement direction and speed.
Definition Velocity.hpp:20
Component for static or destructible walls/obstacles.
Definition Wall.hpp:20
High-level ECS manager providing clean server-side API.
Definition ECSWorld.hpp:122
Entity createEntity()
Create a new entity.
Definition ECSWorld.cpp:67
High-level entity wrapper providing fluent interface.
Definition ECSWorld.hpp:33
Entity & with(const T &component)
Add/set a component to this entity.
bool has() const
Check if this entity has a specific component.
T & get()
Get a component from this entity.
Address getAddress() const
Get the entity's address.
Definition ECSWorld.cpp:39
bool isValid() const
Check if this entity is valid.
Definition ECSWorld.cpp:43
Manages Lua state and script execution for the server.
Definition LuaEngine.hpp:28
BuffType
Types of buffs that can be applied to entities.
Definition Buff.hpp:20
@ PiercingShot
Projectiles pierce through enemies.
@ TripleShot
Fire three projectiles at once.
@ DamageBoost
Increases weapon damage.
@ HomingShot
Projectiles home towards enemies.
@ FireRateBoost
Increases fire rate.
@ MaxHealthIncrease
Permanently increase max health.
@ Shield
Temporary invincibility.
@ HealthRegen
Regenerates health over time.
@ SpeedBoost
Increases movement speed.
@ MultiShot
Shoot in multiple directions.
@ DoubleShot
Fire two projectiles at once.
void bindServerGame(sol::state &lua, ecs::wrapper::ECSWorld *world, LuaEngine *engine)
Bind server-specific game logic functions to Lua.
Declarative request for spawning an entity.
Definition Spawner.hpp:19
std::string scriptPath
Definition Spawner.hpp:23
std::string enemyType
Definition Spawner.hpp:22
float spawnInterval
Definition Spawner.hpp:32
std::vector< SpawnRequest > enemies
Definition Spawner.hpp:31