Refactors script registration to use a map of maps. Map of entity id to map of scripts; script name is key script instance is value.

dev
Joey Pollack 3 years ago
parent 0c2b5b2def
commit 1e38af39aa

@ -34,6 +34,61 @@ Core:
✔ Add run mode interface class @done (9/15/2021, 8:22:35 PM)
✔ Read the window size and position on shutdown and write these to the state file @done (2/8/2022, 4:39:37 PM)
Physics:
✔ Research Box2D as a possible physics library @done (10/27/2021, 7:40:44 PM)
✔ Add Box2D to the project as an external library @done (10/27/2021, 7:40:46 PM)
✔ Add a scene to the tester to test Box2D usage @done (10/28/2021, 2:42:45 PM)
☐ Come up with a way to wrap Box2D into an API
☐ Joint Component to allow parent/child entities to both use the physics system
Scripting:
☐ Allow scripts to interact (calling methods in other scripts)
- In order for a script to be registered with the World API it MUST
- contain a class that inherits from EntityBehavior and that class MUST
- have the same name as the script (case sensitive).
- Only methods in that class will be available to other registered scripts!
✔ Switch to Wren instead of LUA (https://github.com/wren-lang/wren) @high @done(22-11-02 18:56)
✔ Remove SOL @done(22-11-02 18:56)
✔ Script Asset @done(22-11-14 18:19)
Script Managment class:
✘ Manage LUA states @cancelled(22-05-13 17:31)
☐ Initialize new scripts
☐ Run given script with given state
☐ Add any generated errors to the Script object
Interface Class (Core API):
☐ Provide Methods that give access to the C++ code
Audio:
☐ Research the usage of OpenAL
☐ Add OpenAL to the project
☐ Design Audio API
Assets:
✔ Internal Asset Manager @high @done (1/25/2022, 3:58:20 PM)
☐ Document Index.Dat and the AssetIndex class
✔ Move the GenerateFont method from internal_font.h into data_manager.h @done(22-06-29 17:42)
Types:
- Classes that represent each resource Types
✔ Image class @done (9/16/2021, 2:46:34 PM)
✔ Decouple Image class from OGLRenderer @high @done (10/27/2021, 7:41:50 PM)
☐ Font class
☐ Sound class
☐ Animation
✔ Script class @done (1/25/2022, 3:58:28 PM)
Loaders:
- Need class (or classes?) to load resources from the packed format that the pipeline generates
Come up with binary file formats for each type:
☐ .json (This will probably be multiple different formats depending on what the .json file is describing)
☐ Image
☐ Script
☐ Audio
Graphics:
☐ Implement parent transform for all draw methods
☐ Ellipse
@ -85,20 +140,7 @@ GUI:
✔ Add a "New Directory" button @done (11/8/2021, 7:15:51 PM)
✔ Selected files should show up in the text box @done(22-04-18 13:33)
Scripting:
✔ Switch to Wren instead of LUA (https://github.com/wren-lang/wren) @high @done(22-11-02 18:56)
✔ Remove SOL @done(22-11-02 18:56)
✔ Script Asset @done(22-11-14 18:19)
Script Managment class:
✘ Manage LUA states @cancelled(22-05-13 17:31)
☐ Initialize new scripts
☐ Run given script with given state
☐ Add any generated errors to the Script object
Interface Class (Core API):
☐ Provide Methods that give access to the C++ code
ECS:
✔ Figure out how to serialize Entities @done(22-06-28 14:16)
@ -153,16 +195,7 @@ Input:
✔ Port over the Element2D input system and adjust it to use glfw @done (9/8/2021, 8:20:07 PM)
✔ Add the InputManager to the core @done (9/9/2021, 2:57:06 PM)
Physics:
✔ Research Box2D as a possible physics library @done (10/27/2021, 7:40:44 PM)
✔ Add Box2D to the project as an external library @done (10/27/2021, 7:40:46 PM)
✔ Add a scene to the tester to test Box2D usage @done (10/28/2021, 2:42:45 PM)
☐ Come up with a way to wrap Box2D into an API
Audio:
☐ Research the usage of OpenAL
☐ Add OpenAL to the project
☐ Design Audio API
Utils:
@ -171,30 +204,7 @@ Utils:
☐ Add a templated return value to the OK variant of OpRes @low
Assets:
✔ Internal Asset Manager @high @done (1/25/2022, 3:58:20 PM)
☐ Document Index.Dat and the AssetIndex class
✔ Move the GenerateFont method from internal_font.h into data_manager.h @done(22-06-29 17:42)
Types:
- Classes that represent each resource Types
✔ Image class @done (9/16/2021, 2:46:34 PM)
✔ Decouple Image class from OGLRenderer @high @done (10/27/2021, 7:41:50 PM)
☐ Font class
☐ Sound class
☐ Animation
✔ Script class @done (1/25/2022, 3:58:28 PM)
Loaders:
- Need class (or classes?) to load resources from the packed format that the pipeline generates
Come up with binary file formats for each type:
☐ .json (This will probably be multiple different formats depending on what the .json file is describing)
☐ Image
☐ Script
☐ Audio
Asset Pipeline:
☐ Read through the contents folder and generate asset files in a custom format (useable by the engine)
Testbed:
- A special class that is used to unit-test features of the engine

@ -30,6 +30,9 @@ Editor:
✔ Figure out how to make game asset types integrate with editor asset types @critical @done(22-06-27 13:32)
- Probably just wrap the game object in an EditorAsset object if needed
Asset Pipeline:
☐ Read through the contents folder and generate asset files in a custom format (useable by the engine)
Panel System:
☐ Allow for saving custom panel layouts @low
@ -54,6 +57,7 @@ Editor:
✔ Load existing contents @done (3/3/2022, 3:16:21 PM)
✔ Save/Update contents file @done (3/3/2022, 3:16:23 PM)
GUI Panels:
World View:
☐ Add frame feature to center the camera on the selected entity

@ -44,7 +44,7 @@ namespace lunarium
// Generate Code
std::string keys_script = GenerateWrenKeyCodes();
sman.RunSnippet("KeyCodes", keys_script);
sman.RunSnippet("KeyCodes", {}, keys_script);
// DEBUG - SAVE GENERATED SCRIPT TO FILE FOR REVIEW
File::WriteTextFile("key_codes.wren", keys_script);

@ -24,8 +24,11 @@ foreign class VelocityComponent {
foreign class BlockOutComponent {
construct new(entity_id) {}
// Returns the color as a list: [r, g, b, a]
foreign GetColor()
foreign SetColor(r, g, b, a)
// Returns the size as a list: [width, height]
foreign GetSize()
foreign SetSize(w, h)
}

@ -12,36 +12,55 @@ import "Components" for VelocityComponent, BlockOutComponent
class WorldInterface {
static Init() {
__Behaviors = []
__ScriptObjects = {}
System.print("WorldInterface initialized")
}
static RegisterScript(entity_id, script_name, script_class) {
System.print(entity_id.type)
System.print(script_name.type)
System.print(script_class.type)
if (!__ScriptObjects.containsKey(entity_id)){
__ScriptObjects[entity_id] = {}
}
__ScriptObjects[entity_id][script_name] = script_class.new(entity_id)
}
/////////////////////////////////////////////////////////////////////
// EVENTS
/////////////////////////////////////////////////////////////////////
static RegisterBehavior(behavior) {
__Behaviors.add(behavior)
// behavior.OnLoad()
}
// static RegisterBehavior(behavior) {
// __ScriptObjects.add(behavior)
// // behavior.OnLoad()
// }
static DoOnLoad() {
for (behavior in __Behaviors) {
behavior.OnLoad()
for (entity in __ScriptObjects) {
for (script in entity.value) {
script.value.OnLoad()
}
}
}
static DoOnUnload() {
for (behavior in __Behaviors) {
behavior.OnUnload()
for (entity in __ScriptObjects) {
for (script in entity.value) {
script.value.OnUnload()
}
}
}
static Update(dt) {
//System.print("Updating %(__Behaviors.count) behaviors...")
for (behavior in __Behaviors) {
behavior.Update(dt)
for (entity in __ScriptObjects) {
for (script in entity.value) {
script.value.Update(dt)
}
}
}
/////////////////////////////////////////////////////////////////////
@ -55,6 +74,14 @@ class WorldInterface {
static GetBlockOutComponent(entity_id) {
return BlockOutComponent.new(entity_id)
}
static GetScriptObject(entity_id, script_name) {
if (__ScriptObjects.containsKey(entity_id) && __ScriptObjects[entity_id].containsKey(script_name)) {
return __ScriptObjects[entity_id][script_name]
}
return null
}
}

@ -13,6 +13,7 @@
#include <utils/logger.h>
#include <utils/helpers.h>
#include <string.h>
#include <cstdarg>
namespace lunarium
@ -48,10 +49,10 @@ namespace lunarium
mScriptState.RunScript(&world_interface);
// Get class and method handles
mEventHandles.mWIHandle = mScriptState.GetWrenClassHandle("WorldInterface", "WorldInterface");
mEventHandles.mWIInitMethod = mScriptState.GetWrenMethodHandle("Init()");
mEventHandles.mWIRegisterScriptMethod = mScriptState.GetWrenMethodHandle("RegisterScript(_,_,_)");
mEventHandles.mWIDoOnLoadMethod = mScriptState.GetWrenMethodHandle("DoOnLoad()");
mEventHandles.mWIDoOnUnloadMethod = mScriptState.GetWrenMethodHandle("DoOnUnload()");
mEventHandles.mWIUpdateMethod = mScriptState.GetWrenMethodHandle("Update(_)");
@ -73,6 +74,29 @@ namespace lunarium
mScriptState.RunScript(&script);
}
void WorldAPI::RegisterScript(LUUID entity, WrenScript& script)
{
mScriptState.RunScript(&script);
// // Get Handle to script class type to use as second paraneter to RegisterScript
// WrenHandle* pScriptClass = mScriptState.GetWrenClassHandle("WorldInterface", script.GetScriptName());
// std::vector<WrenParameter> params;
// WrenParameter p;
// p.Type = WrenParamType::WPT_STR;
// p.As.String = std::to_string(entity).c_str();
// params.push_back(p);
// p.As.String = script.GetScriptName().c_str();
// params.push_back(p);
// p.Type = WrenParamType::WPT_HANDLE;
// p.As.Handle = pScriptClass;
// params.push_back(p);
// mScriptState.CallWrenMethod(mEventHandles.mWIRegisterScriptMethod, mEventHandles.mWIHandle, params, "WorldInterface.entity_id, script_name, script_class");
std::string script_class = script.GetScriptName();
std::string code = "WorldInterface.RegisterScript(\"" + std::to_string(entity) + "\", \"" + script_class + "\", " + script_class + ")";
mScriptState.RunSnippet("RegisterScript", {{"WorldInterface", "WorldInterface"}, { script_class, script_class }}, code);
}
void WorldAPI::InvokeEvent(Event e, ...)
{
switch (e)

@ -25,7 +25,9 @@ namespace lunarium
{
WrenHandle* mWIHandle;
WrenHandle* mWIInitMethod;
WrenHandle* mWIRegisterScriptMethod;
WrenHandle* mWIDoOnLoadMethod;
WrenHandle* mWIDoOnUnloadMethod;
WrenHandle* mWIUpdateMethod;
@ -42,6 +44,7 @@ namespace lunarium
static OpRes Initialize(World* pWorld);
static void Shutdown();
static void RegisterScript(LUUID entity, WrenScript& script);
static void RunScript(WrenScript& script);
static void InvokeEvent(Event e, ...);

@ -10,11 +10,15 @@
namespace lunarium
{
WrenScript::WrenScript(std::string module_name, std::string code)
: mModuleName(module_name), mCode(code)
WrenScript::WrenScript(std::string script_name,std::string module_name, std::string code)
: mScriptName(script_name), mModuleName(module_name), mCode(code)
{
}
void WrenScript::SetScriptName(std::string name)
{
mScriptName = name;
}
void WrenScript::SetModuleName(std::string name)
{
@ -36,6 +40,11 @@ namespace lunarium
mCode = "";
}
std::string WrenScript::GetScriptName() const
{
return mScriptName;
}
std::string WrenScript::GetModuleName() const
{
return mModuleName;

@ -15,17 +15,24 @@ namespace lunarium
class WrenScript
{
public:
WrenScript(std::string module_name = "", std::string code = "");
WrenScript(std::string script_name = "", std::string module_name = "", std::string code = "");
void SetScriptName(std::string name);
void SetModuleName(std::string name);
void SetScriptCode(std::string code);
void AppendScriptCode(std::string code);
void ClearScript();
/// In order for a script to be registered with the World API it MUST
/// contain a class that inherits from EntityBehavior and that class MUST
/// have the same name as the script (case sensitive).
/// Only methods in that class will be available to other registered scripts!
std::string GetScriptName() const;
std::string GetModuleName() const;
std::string GetScriptCode() const;
private:
std::string mScriptName;
std::string mModuleName;
std::string mCode;
};

@ -92,6 +92,7 @@ namespace lunarium
case WrenParamType::WPT_DOUBLE: wrenSetSlotDouble(mpVM, i + 1, params[i].As.Double); break;
case WrenParamType::WPT_BOOL: wrenSetSlotBool(mpVM, i + 1, params[i].As.Bool); break;
case WrenParamType::WPT_STR: wrenSetSlotString(mpVM, i + 1, params[i].As.String); break;
case WrenParamType::WPT_HANDLE: wrenSetSlotHandle(mpVM, i + 1, params[i].As.Handle); break;
default: Logger::Warn(mLogCat, "Unknown wren parameter type: %d", (int)params[i].Type);
}
}
@ -135,7 +136,7 @@ namespace lunarium
}
void WrenState::RunSnippet(std::string name, std::string code)
void WrenState::RunSnippet(std::string name, std::vector<Import> imports, std::string code)
{
if (!mpVM)
{
@ -143,7 +144,15 @@ namespace lunarium
return;
}
WrenInterpretResult result = wrenInterpret(mpVM, name.c_str(), code.c_str());
std::string import_code = "";
for (Import import : imports)
{
import_code += "import \"" + import.Module + "\" for " + import.Classes + "\n";
}
import_code += "\n";
std::string final_code = import_code + code;
WrenInterpretResult result = wrenInterpret(mpVM, name.c_str(), final_code.c_str());
switch (result)
{
case WREN_RESULT_COMPILE_ERROR: Logger::Trace(mLogCat, "Snippet compile error in module: %s", name.c_str()); break;

@ -24,6 +24,7 @@ namespace lunarium
WPT_DOUBLE,
WPT_BOOL,
WPT_STR,
WPT_HANDLE,
};
struct WrenParameter
@ -36,7 +37,8 @@ namespace lunarium
int Int;
char Char;
bool Bool;
char* String;
const char* String;
WrenHandle* Handle;
} As;
};
@ -76,6 +78,12 @@ namespace lunarium
}
};
struct Import
{
std::string Module;
std::string Classes;
};
public:
~WrenState();
@ -87,7 +95,7 @@ namespace lunarium
void RegisterForeignClass(ForeignClassDesc class_desc);
void RunScript(WrenScript* script);
void RunSnippet(std::string name, std::string code);
void RunSnippet(std::string name, std::vector<Import> imports, std::string code);
WrenHandle* GetWrenClassHandle(std::string from_module, std::string class_name);
WrenHandle* GetWrenMethodHandle(std::string method_signature); // signature example (mehtod takes 2 parameters): method_name(_,_)

@ -104,42 +104,34 @@ namespace lunarium
rigid_body.pBody = mpPhysicsWorld->CreateBody(&rigid_body.Defintion);
// Handle collision components
if (mECSRegistry.all_of<CollisionComponent>(entity))
{
auto& comp = mECSRegistry.get<CollisionComponent>(entity);
switch (comp.Type)
{
case CollisionComponent::ShapeType::Box:
{
b2PolygonShape Shape;
Shape.SetAsBox(comp.Width / scale_factor, comp.Height / scale_factor);
b2FixtureDef fixtureDef;
fixtureDef.shape = &Shape;
fixtureDef.isSensor = comp.IsSensor;
fixtureDef.density = comp.Density;
fixtureDef.friction = comp.Friction;
fixtureDef.restitution = comp.Restitution;
fixtureDef.filter.groupIndex = comp.CollisionGroup;
rigid_body.pBody->CreateFixture(&fixtureDef);
} break;
b2PolygonShape Shape;
switch (comp.Type)
{
case CollisionComponent::ShapeType::Box:
Shape.SetAsBox(comp.Width / scale_factor, comp.Height / scale_factor); break;
case CollisionComponent::ShapeType::Circle:
{
b2CircleShape Shape;
Shape.m_radius = comp.Radius / scale_factor;
Shape.m_radius = comp.Radius / scale_factor; break;
}
b2FixtureDef fixtureDef;
fixtureDef.shape = &Shape;
fixtureDef.isSensor = comp.IsSensor;
fixtureDef.density = comp.Density;
fixtureDef.friction = comp.Friction;
fixtureDef.restitution = comp.Restitution;
rigid_body.pBody->CreateFixture(&fixtureDef);
} break;
b2Fixture* fixture = rigid_body.pBody->CreateFixture(&fixtureDef);
}
// Associate the fixture to it's entity so that collision callbacks can work
mEntitiesByColliders[fixture] = GetEntity(entity);
}
}
@ -153,10 +145,11 @@ namespace lunarium
// If were attached to the editor we need to get the script from the editor's content manager
#if !BUILD_NO_EDITOR
// TODO: Modify to add all scripts contained in the ScriptComponent (eventually they will have lists of scripts instead of just one)
editor::Script* pScript = (editor::Script*) editor::ContentManager::GetInstance().GetAsset(script_comp.ScriptID);
WrenScript script(pScript->GetScriptFile().filename().string().c_str(), pScript->GetScript());
// mScriptState.RunScript(&script);
WorldAPI::RunScript(script);
std::string name = pScript->GetScriptFile().stem().string();
WrenScript script(name.c_str(), name.c_str(), pScript->GetScript());
WorldAPI::RegisterScript(GetEntity(entity)->GetUUID(), script);
#else
// Get Binary assets
#endif
@ -174,6 +167,8 @@ namespace lunarium
delete mpPhysicsWorld;
mpPhysicsWorld = nullptr;
mEntitiesByColliders.clear();
}
void World::SetRunMode(RunMode mode)
@ -224,7 +219,7 @@ namespace lunarium
float scale_factor = WorldSettings.Physics.PhysicsScaleFactor;
transform.Position = glm::vec3(rigid_body.pBody->GetPosition().x * scale_factor, rigid_body.pBody->GetPosition().y * scale_factor, 0.0f);
transform.Rotation.z = rigid_body.pBody->GetAngle();
transform.Rotation.z = rigid_body.pBody->GetAngle() * -1.0f;
}
}
@ -297,6 +292,12 @@ namespace lunarium
return mEntitiesByUUID[id];
}
Entity* World::GetEntity(entt::entity entt_id)
{
return GetEntity(mECSRegistry.get<UUIDComponent>(entt_id).UUID);
}
unsigned int World::GetNumEntities() const
{
return mEntities.size();

@ -91,6 +91,7 @@ namespace lunarium
LUUID CreateEntity();
void RemoveEntity(LUUID id);
Entity* GetEntity(LUUID id);
Entity* GetEntity(entt::entity entt_id);
unsigned int GetNumEntities() const;
std::vector<Entity*>::iterator EntitiesBegin();
bool EntitiesIsEnd(std::vector<Entity*>::iterator& iter);
@ -122,6 +123,7 @@ namespace lunarium
entt::registry mECSRegistry;
std::vector<Entity*> mEntities;
std::map<LUUID, Entity*> mEntitiesByUUID;
std::map<b2Fixture*, Entity*> mEntitiesByColliders; // Needed for collision detection callbacks
FrameBuffer* mFrameBuffer;
OrthographicCamera* mpActiveCamera;
b2World* mpPhysicsWorld;

Loading…
Cancel
Save