Explore Phi

Save Philand

User can save Objects to Philand


The save function can be used to update philand by putting the objects and links that you want to write to the contract.
* @title save
* @notice Function for save users map edition
* @param name : ens name
* @param removeIndexArray : Array of Object index
* @param objectData : Array of Object struct (address contractAddress, uint256 tokenId, uint256 xStart, uint256 yStart)
* @param link : Array of Link struct(stirng title, string url)
* @param contractAddress : if you dont use, should be 0
* @param tokenId : if you dont use, should be 0
* @dev _removeUnUsedUserObject: clear delete empty array
function save(
string memory name,
uint256[] memory removeIndexArray,
Object[] memory objectDatas,
Link[] memory links,
address wcontractAddress,
uint256 wtokenId,
address bcontractAddress,
uint256 btokenId
) external nonReentrant onlyNotLocked onlyPhilandOwner(name) {
_batchRemoveAndWrite(name, removeIndexArray, objectDatas, links);
if (wcontractAddress != address(0) && wtokenId != 0) {
_changeWallPaper(name, wcontractAddress, wtokenId);
if (bcontractAddress != address(0) && btokenId != 0) {
_changeBasePlate(name, bcontractAddress, btokenId);
emit Save(name, msg.sender);
Save Land

Write object

* @title writeObjectToLand
* @notice Return philand object
* @param name : ens name
* @param objectData : Object (address contractAddress,uint256 tokenId, uint256 xStart, uint256 yStart)
* @param link : Link (stirng title, string url)
* @dev NFT must be deposited in the contract before writing.
function writeObjectToLand(
string memory name,
Object memory objectData,
Link memory link
) public onlyNotLocked onlyPhilandOwner(name) onlyDepositObject(name, objectData) {
// Check the number of deposit NFTs to write object
_checkDepositAvailable(name, objectData.contractAddress, objectData.tokenId);
// Check the contractAddress is whitelisted.
if (!_whitelist[objectData.contractAddress]) revert InvalidWhitelist();
IObject _object = IObject(objectData.contractAddress);
// Object contract requires getSize functions for x,y,z
IObject.Size memory size = _object.getSize(objectData.tokenId);
ObjectInfo memory writeObjectInfo = ObjectInfo(
objectData.xStart + size.x,
objectData.yStart + size.y,
// Check map range MapSettings
// Check Write Object dosen't collide with previous written objects
_checkCollision(name, writeObjectInfo);
emit WriteObject(name, objectData.contractAddress, objectData.tokenId, objectData.xStart, objectData.yStart);
emit WriteLink(name, objectData.contractAddress, objectData.tokenId, link.title, link.url, link.data);
Each object has the ability to have a link function, which can have a title, link, and data columns. The link function is typically used to associate an object with a web page
// Each object can save with Link
struct Link {
string title;
string url;
uint256 data;

Remove Object

* @title _removeUnUsedUserObject
* @notice Functions for erase the 0 array value that has already been deleted.
* @param name : ens name
* @dev execute when writing an object.
* @notion Erases the 0 array value that has already been deleted.
function _removeUnUsedUserObject(string memory name) private {
uint256 index = 0;
bool check = false;
uint256 objectLength = userObject[name].length;
ObjectInfo[] memory _userObjects = userObject[name];
ObjectInfo[] memory newUserObjects = new ObjectInfo[](objectLength);
for (uint256 i = 0; i < objectLength; ++i) {
// Erases the address(0) array that has already been deleted.
if (_userObjects[i].contractAddress == address(0)) {
check = true;
newUserObjects[index] = _userObjects[i];
index = index + 1;
if (check) {
for (uint256 i = 0; i < objectLength; ++i) {
if (_userObjects[i].contractAddress != address(0)) {
_removeObjectFromLand(name, i);
delete userObject[name];
for (uint256 i = 0; i < index; ++i) {
_writeObjectToLand(name, newUserObjects[i]);

Floating Object (transparency)

Some objects may appear to be floating in the scene. In these cases, the objects are written to the contract in the vertical direction, and transparency is applied to make the objects behind them visible. This allows for a more realistic and immersive experience

Collision Check

When writing objects to the contract, collision detection between rectangles is performed. The current implementation uses a simple method for detecting collisions, but we are always looking for better ways to do this. In future implementations, we may change the collision detection to use a more efficient way
* @title checkCollision
* @notice Functions for collision detection
* @param name : Ens name
* @param writeObjectInfo : Information about the object you want to write.
* @dev execute when writing an object.
function _checkCollision(string memory name, ObjectInfo memory writeObjectInfo) private view {
uint256 objectLength = userObject[name].length;
ObjectInfo[] memory _userObjects = userObject[name];
if (objectLength == 0) {
for (uint256 i = 0; i < objectLength; ++i) {
// Skip if already deleted
if (_userObjects[i].contractAddress == address(0)) {
// Rectangular objects do not collide when any of the following four conditions are satisfied
if (
writeObjectInfo.xEnd <= _userObjects[i].xStart ||
_userObjects[i].xEnd <= writeObjectInfo.xStart ||
writeObjectInfo.yEnd <= _userObjects[i].yStart ||
_userObjects[i].yEnd <= writeObjectInfo.yStart
) {
} else {
revert ObjectCollision({
writeObjectInfo: writeObjectInfo,
userObjectInfo: _userObjects[i],
errorBoader: "invalid objectInfo"

In this case, there is no collision .

check collision