Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #8: no modules on root #10

Merged
merged 14 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 37 additions & 16 deletions core/smart-object-framework/mud.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mudConfig } from "@latticexyz/world/register";

export default mudConfig({
namespace: "SmartObject_v0",
excludeSystems: ["EveSystem"],
systems: {
EntityCore: {
Expand All @@ -27,8 +28,10 @@ export default mudConfig({
keySchema: { "typeId": "uint8" },
valueSchema: {
doesExists: "bool",
typeName: "bytes32"
}
typeName: "bytes32",
},
storeArgument: true,
tableIdArgument: true,
},
/**
* Used to register an entity by its type
Expand All @@ -38,7 +41,9 @@ export default mudConfig({
valueSchema: {
doesExists: "bool", //Tracks the entity which is no longer valid
entityType: "uint8"
}
},
storeArgument: true,
tableIdArgument: true,
},
/**
* Used to enforce association/tagging possibility by entity types
Expand All @@ -49,29 +54,35 @@ export default mudConfig({
keySchema: { "entityType": "uint8", "taggedEntityType": "uint8" },
valueSchema: {
isAllowed: "bool"
}
},
storeArgument: true,
tableIdArgument: true,
},
/**
* Used to tag/map an entity by its tagged entityIds
* eg: Similar objects can be grouped as Class, and tagged with a classId.
* One entity can be tagged with multiple classIds
*/
EntityMapTable: {
EntityMap: {
MerkleBoy marked this conversation as resolved.
Show resolved Hide resolved
keySchema: { "entityId": "uint256" },
valueSchema: {
taggedEntityIds: "uint256[]"
}
},
storeArgument: true,
tableIdArgument: true,
},
/**
* Used to associate a entity with a specific set of modules and hooks
* to inherit the functionality of those modules(systems) and hooks
*/
EntityAssociationTable: {
EntityAssociation: {
keySchema: { "entityId": "uint256" },
valueSchema: {
moduleIds: "uint256[]",
hookIds: "uint256[]"
}
},
storeArgument: true,
tableIdArgument: true,
},

/************************
Expand All @@ -86,18 +97,22 @@ export default mudConfig({
//Can add functions registered in this system if we need granular control
moduleName: "bytes16",
doesExists: "bool",
}
},
storeArgument: true,
tableIdArgument: true,
},

/**
* Only used for lookup purpose to find the moduleIds associated with a system
* TODO - Do we need this table?
*/
ModuleSystemLookupTable: {
ModuleSystemLookup: {
keySchema: { "moduleId": "uint256" },
valueSchema: {
systemIds: "bytes32[]"
}
},
storeArgument: true,
tableIdArgument: true,
},

/************************
Expand All @@ -113,29 +128,35 @@ export default mudConfig({
isHook: "bool",
systemId: "ResourceId", //Callback systemId of the hook
functionSelector: "bytes4" //Callback functionId of the hook
}
},
storeArgument: true,
tableIdArgument: true,
},
/**
* Used to map the function to be executed before a existing function in a system by hookId
*/
HookTargetBeforeTable: {
HookTargetBefore: {
keySchema: { "hookId": "uint256", "targetId": "uint256" }, // targetId - uint256(keccak(systemSelector, functionId))
valueSchema: {
hasHook: "bool",
systemSelector: "ResourceId", //Target system to hook against
functionSelector: "bytes4" //Target function to hook against
}
},
storeArgument: true,
tableIdArgument: true,
},
/**
* Used to map the function to be executed after a existing function in a system by hookId
*/
HookTargetAfterTable: {
HookTargetAfter: {
keySchema: { "hookId": "uint256", "targetId": "uint256" },
valueSchema: {
hasHook: "bool",
systemSelector: "ResourceId", //Target system to hook against
functionSelector: "bytes4" //Target function to hook against
}
},
storeArgument: true,
0xxlegolas marked this conversation as resolved.
Show resolved Hide resolved
tableIdArgument: true,
0xxlegolas marked this conversation as resolved.
Show resolved Hide resolved
},
},
});
111 changes: 111 additions & 0 deletions core/smart-object-framework/src/SmartObjectFrameworkModule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.21;

import { ResourceIds } from "@latticexyz/store/src/codegen/tables/ResourceIds.sol";
import { ResourceId } from "@latticexyz/store/src/ResourceId.sol";
import { Module } from "@latticexyz/world/src/Module.sol";
import { WorldResourceIdLib } from "@latticexyz/world/src/WorldResourceId.sol";
import { IBaseWorld } from "@latticexyz/world/src/codegen/interfaces/IBaseWorld.sol";

import {
SMART_OBJECT_MODULE_NAME as MODULE_NAME,
SMART_OBJECT_MODULE_NAMESPACE as MODULE_NAMESPACE,
SMART_OBJECT_MODULE_NAMESPACE_ID as MODULE_NAMESPACE_ID
} from "./constants.sol";
import "./utils.sol";

import { EntityCore } from "./systems/core/EntityCore.sol";
import { ModuleCore } from "./systems/core/ModuleCore.sol";
import { HookCore } from "./systems/core/HookCore.sol";

import { EntityAssociation } from "./codegen/tables/EntityAssociation.sol";
import { EntityMap } from "./codegen/tables/EntityMap.sol";
import { EntityTable } from "./codegen/tables/EntityTable.sol";
import { EntityType } from "./codegen/tables/EntityType.sol";
import { EntityTypeAssociation } from "./codegen/tables/EntityTypeAssociation.sol";
import { HookTable } from "./codegen/tables/HookTable.sol";
import { HookTargetAfter } from "./codegen/tables/HookTargetAfter.sol";
import { HookTargetBefore } from "./codegen/tables/HookTargetBefore.sol";
import { ModuleSystemLookup } from "./codegen/tables/ModuleSystemLookup.sol";
import { ModuleTable } from "./codegen/tables/ModuleTable.sol";


contract SmartObjectFrameworkModule is Module {

error SmartObjectFrameworkModule_InvalidNamespace(bytes14 namespace);

address immutable registrationLibrary = address(new SmartObjectFrameworkModuleRegistrationLibrary());

function getName() public pure returns (bytes16) {
return MODULE_NAME;
}

function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return super.supportsInterface(interfaceId);
}
function _requireDependencies() internal view {
// Require other modules to be installed
// (not the case here)
//
// if (!isInstalled(bytes16("MODULE_NAME"), new bytes(0))) {
// revert Module_MissingDependency(string(bytes.concat("MODULE_NAME")));
// }
}

function install(bytes memory encodedArgs) public {
// Require the module to not be installed with these args yet
requireNotInstalled(__self, encodedArgs);

// Extract args
bytes14 namespace = abi.decode(encodedArgs, (bytes14));

// Require the namespace to not be the module's namespace
if (namespace == MODULE_NAMESPACE) {
revert SmartObjectFrameworkModule_InvalidNamespace(namespace);
}

// Require dependencies
_requireDependencies();

// Register the smart object framework's tables and systems
IBaseWorld world = IBaseWorld(_world());
(bool success, bytes memory returnedData) = registrationLibrary.delegatecall(abi.encodeCall(SmartObjectFrameworkModuleRegistrationLibrary.register, (world, namespace)));
require(success, string(returnedData));
MerkleBoy marked this conversation as resolved.
Show resolved Hide resolved

// Transfer ownership of the namespace to the caller
ResourceId namespaceId = WorldResourceIdLib.encodeNamespace(namespace);
world.transferOwnership(namespaceId, _msgSender());
}

// would be a very bad idea (see issue #5 on Github)
function installRoot(bytes memory) public pure {
revert Module_RootInstallNotSupported();
}
}

contract SmartObjectFrameworkModuleRegistrationLibrary {
using Utils for bytes14;
/**
* Register systems and tables for a new smart object framework in a given namespace
*/
function register(IBaseWorld world, bytes14 namespace) public {
// Register the namespace
world.registerNamespace(WorldResourceIdLib.encodeNamespace(namespace));
// Register the tables
EntityAssociation.register(namespace.entityAssociationTableId());
EntityMap.register(namespace.entityMapTableId());
EntityTable.register(namespace.entityTableTableId());
EntityType.register(namespace.entityTypeTableId());
EntityTypeAssociation.register(namespace.entityTypeAssociationTableId());
HookTable.register(namespace.hookTableTableId());
HookTargetAfter.register(namespace.hookTargetAfterTableId());
HookTargetBefore.register(namespace.hookTargetBeforeTableId());
ModuleSystemLookup.register(namespace.moduleSystemLookupTableId());
ModuleTable.register(namespace.moduleTableTableId());

// Register a new Systems suite
world.registerSystem(namespace.entityCoreSystemId(), new EntityCore(), true);
world.registerSystem(namespace.moduleCoreSystemId(), new ModuleCore(), true);
world.registerSystem(namespace.hookCoreSystemId(), new HookCore(), true);
}
}
Loading