0

I'm trying to do something very simple. I want to make a structure that holds the data for a player.

Within that data, I want an array to store things like its inventory, and its current eggs/monsters.

Yet I cannot interact with arrays at all, I'm constantly getting issues. Can someone tell me what I'm doing wrong and why it won't let me read and return arrays?

contract EtherMon{ 
    uint public starterEgg;
    address public owner;



    struct player{
        uint256 goldAmount;
      uint[10] listOfEggs;
        bool eggCoolDown;
        uint eggTime;
        uint eggID;
        bool battleCoolDown;
        bool breedingCoolDown;
        uint[] ownedEthermon;
    }

      mapping (address => player) public listOfPlayers;

    function EtherMon(){
        owner = msg.sender;

    }

    function createAccount(){


     starterEgg = block.timestamp % 10;

     listOfPlayers[msg.sender].goldAmount  = 100;
     listOfPlayers[msg.sender].listOfEggs[0] = starterEgg;


        }



  function getCurrentEggs() returns (uint[]) {
 uint length =  listOfPlayers[msg.sender].listOfEggs.length;
 uint[] eggArray;
            for(uint i = 0; i < length; i++){
               eggArray[i] =  listOfPlayers[msg.sender].listOfEggs[i];
            }
            return eggArray;
        }

    }

Basically I just want to be able to...

  1. Call CreateAccount and it stores a random uint into the array that stores the eggs a player holds
  2. Pull that egg data from the mapping and see it/change it

Can someone give me an example of a structure that holds an array (and mapping because it seems I can use a mapping within a struct but have issues with dynamic arrays) and has getter and setter functions?

2 Answers 2

1

Here are some patterns that might help you out.

pragma solidity ^0.4.15;

contract Storage {

    struct PlayerStruct {
        uint meaningless;
        uint[] dynamicList;
        uint[10] fixedList;
        mapping(bytes32 => uint) keyToUintMap;
    }

    mapping(address => PlayerStruct) public playerStructs;

    function getPlayerDynListLength(address player) public constant returns(uint count) {
        return playerStructs[player].dynamicList.length;
    }

    function appendPlayerDynList(address player, uint value) public returns(uint length) {
        return playerStructs[player].dynamicList.push(value);
    }

    function setPlayerDynFixedList(address player, uint index, uint value) public returns(bool success) {
        require(index <= 9);
        playerStructs[player].fixedList[index] = value;
        return true;
    }

    function getPlayerDynamicListElement(address player, uint index) public constant returns(uint value) {
        return playerStructs[player].dynamicList[index];
    }

    function setPlayerMappedElement(address player, bytes32 key, uint value) public returns(bool success) {
        playerStructs[player].keyToUintMap[key] = value;
        return true;
    }

    function getPlayerMappedElement(address player, bytes32 key) public constant returns(uint value) {
        return playerStructs[player].keyToUintMap[key];
    }

}

Update:

Here it is in Remix to show it working:

enter image description here

Hope it helps.

3
  • Thank you Rob! This is helpful, but it looks exactly like what I was trying to do (syntax wise) and more broken apart. I still get the same error though from Remix IDE - undefined errored: VM error: invalid opcode. The constructor should be payable if you send value. The execution might have thrown. Debug the transaction to get more information.
    – Zach
    Oct 17, 2017 at 19:18
  • Based on your description, the issue is in the request, not the contract. You can generate the invalid OPCODE any number of ways. Possibly the most obvious is to walk off the end of an array. So, if an array has 2 elements (0,1) and you ask for the index "2" then it will return an error because the requested element doesn't exist. Oct 17, 2017 at 19:38
  • Picture is using the "old" Remix at yann300.github.io where you can band away on contracts and satisfy yourself that your contracts work as expected. Calling them from JS is another source of potential problems. :-) Oct 17, 2017 at 19:40
0

You should modify your getCurrentEggs() function like this:

function getCurrentEggs() constant returns (uint[]) {
 uint length =  listOfPlayers[msg.sender].listOfEggs.length;
 uint[] memory eggArray = new uint[](length);
            for(uint i = 0; i < length; i++){
               eggArray[i] =  listOfPlayers[msg.sender].listOfEggs[i];
            }
            return eggArray;
        }
 }

1- Since the function does note modify any state variable, it should be marked as constant.

2- You are not initializing the eggArray correctly.For more info, check this other question: How to initialize an empty array and push items into it?

Update: Also, I'm not sure why you are iterating listOfEggs, adding each element to a new array and then returning the array while you could just do:

function getCurrentEggs() constant returns (uint[10]) {
    return listOfPlayers[msg.sender].listOfEggs;
    }
3
  • Ok. Thanks. How does storing an Array in Memory differ from using a dynamic array? In terms of cost of storage? It seems pretty confusing, we have arrays and mappings, but they cost differently and now we have memory array and dynamic arrays. I'm just kinda confused
    – Zach
    Oct 17, 2017 at 19:19
  • I tried doing the return listOfPlayer[msg.sender].listOfEggs and it gave an error about the type. But your code works when I use memory eggArray.
    – Zach
    Oct 17, 2017 at 19:26
  • You are mixing concepts up. I recommend you give the Solidity docs a quick look. Also, just updated my answer as there's a much simpler way of doing this. Oct 17, 2017 at 19:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.