Contract Name:
ProjectNineData
Contract Source Code:
File 1 of 1 : ProjectNineData
/**
* _ _ _ _ _ _ _ _
* /\ \ /\ \ /\ \ /\ \ /\ \ /\ \ /\ \ / /\
* / \ \ / \ \ / \ \ \ \ \ / \ \ / \ \ \_\ \ / / \
* / /\ \ \ / /\ \ \ / /\ \ \ /\ \_\ / /\ \ \ / /\ \ \ /\__ \ / / /\ \
* / / /\ \_\ / / /\ \_\ / / /\ \ \ / /\/_// / /\ \_\ / / /\ \ \ / /_ \ \ /_/ /\ \ \
* / / /_/ / // / /_/ / / / / / \ \_\ _ / / / / /_/_ \/_/ / / / \ \_\ / / /\ \ \ \ \ \_\ \ \
* / / /__\/ // / /__\/ / / / / / / //\ \ / / / / /____/\ / / / \/_/ / / / \/_/ \ \/__\ \ \
* / / /_____// / /_____/ / / / / / / \ \_\ / / / / /\____\/ / / / / / / \_____\ \ \
* / / / / / /\ \ \ / / /___/ / / / / /_/ / / / / /______ / / /________ / / / \ \ \
* / / / / / / \ \ \/ / /____\/ / / / /__\/ / / / /_______\/ / /_________\/_/ / \ \ \
* \/_/ \/_/ \_\/\/_________/ \/_______/ \/__________/\/____________/\_\/ \_\/
*
* On-chain Project-9 NFT, by SoftWave.
**/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ProjectNineData {
address payable internal deployer;
address payable public nftContract;
bool private contractLocked = false;
uint256 private constant CANVAS_SIZE = 24;
uint256 private constant PIXEL_DATA_SIZE = CANVAS_SIZE * CANVAS_SIZE * 3;
uint256 public constant MAX_LIMIT = 2222;
Coordination public updateCoord;
struct Trait {
string traitType;
string value;
}
struct Coordination {
uint256 startX;
uint256 startY;
uint256 width;
uint256 height;
}
struct NineData {
bytes pixelData;
Trait[] traits;
bytes equippedWeapon;
uint256 xp;
}
mapping(uint256 => NineData) private nineData;
modifier onlyNFTContract() {
require(msg.sender == nftContract, "Only NFTContract.");
_;
}
modifier onlyDeployer() {
require(msg.sender == deployer, "Only deployer.");
_;
}
modifier unlocked() {
require(!contractLocked, "Contract is locked.");
_;
}
constructor() {
deployer = payable(msg.sender);
}
function setNFTContract(address contractAddress) external onlyDeployer {
nftContract = payable(contractAddress);
}
function setUpdateCoordination(
uint256 startX,
uint256 startY,
uint256 width,
uint256 height
) external onlyDeployer {
require(startX + width <= CANVAS_SIZE, "Width out of bounds");
require(startY + height <= CANVAS_SIZE, "Height out of bounds");
updateCoord = Coordination(startX, startY, width, height);
}
function lockContract() external onlyDeployer unlocked {
contractLocked = true;
}
function storePixelData(uint256 tokenId, bytes memory pixelData)
external
onlyDeployer
unlocked
{
require(tokenId < MAX_LIMIT, "Invalid tokenId");
require(
pixelData.length == PIXEL_DATA_SIZE,
"Invalid pixel data length"
);
nineData[tokenId].pixelData = pixelData;
}
function batchStorePixelData(
uint256[] memory tokenIds,
bytes[] memory pixelDataArray
) external onlyDeployer unlocked {
require(tokenIds.length == pixelDataArray.length, "Mismatched arrays");
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
bytes memory pixelData = pixelDataArray[i];
require(tokenId < MAX_LIMIT, "Invalid tokenId");
require(
pixelData.length == PIXEL_DATA_SIZE,
"Invalid pixel data length"
);
nineData[tokenId].pixelData = pixelData;
}
}
function storeTraits(uint256 tokenId, Trait[] memory traits)
external
onlyDeployer
unlocked
{
require(traits.length > 0, "Traits cannot be empty");
delete nineData[tokenId].traits;
for (uint256 i = 0; i < traits.length; i++) {
nineData[tokenId].traits.push(traits[i]);
}
}
function batchStoreTraits(
uint256[] memory tokenIds,
Trait[][] memory traitsArray
) external onlyDeployer unlocked {
require(tokenIds.length == traitsArray.length, "Mismatched arrays");
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
Trait[] memory traits = traitsArray[i];
delete nineData[tokenId].traits;
for (uint256 j = 0; j < traits.length; j++) {
nineData[tokenId].traits.push(traits[j]);
}
}
}
function getTraits(uint256 tokenId) external view returns (string memory) {
require(nineData[tokenId].traits.length > 0, "Traits not set");
string memory jsonTraits = "[";
for (uint256 i = 0; i < nineData[tokenId].traits.length; i++) {
jsonTraits = string.concat(
jsonTraits,
'{"trait_type": "',
nineData[tokenId].traits[i].traitType,
'", "value": "',
nineData[tokenId].traits[i].value,
'"}'
);
if (i < nineData[tokenId].traits.length - 1) {
jsonTraits = string.concat(jsonTraits, ",");
}
}
jsonTraits = string.concat(jsonTraits, "]");
return jsonTraits;
}
function getNineData(uint256 tokenId) external view returns (bytes memory) {
require(tokenId < MAX_LIMIT, "Invalid tokenId");
require(
nineData[tokenId].pixelData.length == PIXEL_DATA_SIZE,
"Pixel data not set"
);
return nineData[tokenId].pixelData;
}
function updateWeapon(uint256 tokenId, bytes memory colors) external onlyNFTContract {
uint256 area = updateCoord.width * updateCoord.height;
require(colors.length == area * 3, "Colors array length mismatch");
bytes storage weapon = nineData[tokenId].equippedWeapon;
require(weapon.length == PIXEL_DATA_SIZE, "Invalid pixel data");
for (uint256 row = 0; row < updateCoord.height; row++) {
for (uint256 col = 0; col < updateCoord.width; col++) {
uint256 x = updateCoord.startX + col;
uint256 y = updateCoord.startY + row;
uint256 pixelIndex = (y * 24 + x) * 3;
uint256 colorIndex = (row * updateCoord.width + col) * 3;
weapon[pixelIndex] = colors[colorIndex];
weapon[pixelIndex + 1] = colors[colorIndex + 1];
weapon[pixelIndex + 2] = colors[colorIndex + 2];
}
}
if(nineData[tokenId].xp < 3)
nineData[tokenId].xp += 1;
}
function updateTrait(uint256 tokenId, string memory traitType, string memory value) external onlyNFTContract {
Trait[] storage traits = nineData[tokenId].traits;
for (uint256 i = 0; i < traits.length; i++) {
if (keccak256(bytes(traits[i].traitType)) == keccak256(bytes(traitType))) {
traits[i].value = value;
return;
}
}
traits.push(Trait(traitType, value));
}
function getEquippedWeapon(uint256 tokenId) external view returns (bytes memory) {
return nineData[tokenId].equippedWeapon;
}
function train(uint256 tokenId) external onlyNFTContract {
if(nineData[tokenId].xp < 3)
nineData[tokenId].xp += 1;
}
function exercise(uint256 tokenId) external onlyNFTContract {
if(nineData[tokenId].xp < 3)
nineData[tokenId].xp += 1;
}
function getXP(uint256 tokenId) external view returns (uint256) {
return nineData[tokenId].xp;
}
}