com.norman0406.slimgress.API.Game.GameState.java Source code

Java tutorial

Introduction

Here is the source code for com.norman0406.slimgress.API.Game.GameState.java

Source

/***********************************************************************
*
* Slimgress: Ingress API for Android
* Copyright (C) 2013 Norman Link <norman.link@gmx.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
***********************************************************************/

package com.norman0406.slimgress.API.Game;

import java.util.LinkedList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.google.common.geometry.S2LatLng;
import com.google.common.geometry.S2LatLngRect;
import com.norman0406.slimgress.API.Common.Location;
import com.norman0406.slimgress.API.Common.Team;
import com.norman0406.slimgress.API.Common.Utils;
import com.norman0406.slimgress.API.Plext.PlextBase;
import com.norman0406.slimgress.API.Interface.*;
import com.norman0406.slimgress.API.GameEntity.*;
import com.norman0406.slimgress.API.Item.*;
import com.norman0406.slimgress.API.Knobs.KnobsBundle;
import com.norman0406.slimgress.API.Player.*;

public class GameState {
    private Interface mInterface;
    private Handshake mHandshake;
    private KnobsBundle mKnobs;
    private Inventory mInventory;
    private World mWorld;
    private Agent mAgent;
    private List<PlextBase> mPlexts;
    private String mLastSyncTimestamp;
    private Location mLocation;

    public GameState() {
        mInterface = new Interface();
        mInventory = new Inventory();
        mWorld = new World();
        mPlexts = new LinkedList<PlextBase>();
        mLastSyncTimestamp = "0";
    }

    public void clear() {
        mInventory.clear();
        mWorld.clear();
        mPlexts.clear();
        mLastSyncTimestamp = "0";
    }

    public void updateLocation(Location location) {
        mLocation = location;
    }

    public final Location getLocation() {
        return mLocation;
    }

    private synchronized void processGameBasket(GameBasket gameBasket) {
        if (gameBasket == null)
            Log.w("Game", "game basket is invalid");
        else {
            mInventory.processGameBasket(gameBasket);
            mWorld.processGameBasket(gameBasket);

            // update player data
            PlayerEntity playerEntity = gameBasket.getPlayerEntity();
            if (playerEntity != null && mAgent != null)
                mAgent.update(playerEntity);
        }
    }

    public synchronized void checkInterface() {
        // check
        if (mHandshake == null || !mHandshake.isValid())
            throw new RuntimeException("invalid handshake data");

        // get agent
        if (mAgent == null)
            mAgent = mHandshake.getAgent();
    }

    public Interface.AuthSuccess intAuthenticate(String token) {
        return mInterface.authenticate(token);
    }

    public synchronized void intHandshake(final Handler handler) {
        mInterface.handshake(new Handshake.Callback() {
            @Override
            public void handle(Handshake handshake) {
                mHandshake = handshake;
                mKnobs = mHandshake.getKnobs();

                Message msg = new Message();
                Bundle bundle = new Bundle();
                bundle.putBoolean("Successful", mHandshake.isValid());

                if (!mHandshake.isValid()) {
                    String errString;
                    if (mHandshake.getPregameStatus() == Handshake.PregameStatus.ClientMustUpgrade)
                        errString = "Client must upgrade";
                    else if (mHandshake.getAgent() == null)
                        errString = "Invalid agent data";
                    else
                        errString = "Unknown error";

                    bundle.putString("Error", errString);
                }

                msg.setData(bundle);
                handler.sendMessage(msg);
            }
        });
    }

    public void intGetInventory(final Handler handler) {
        try {
            checkInterface();

            // create params
            JSONObject params = new JSONObject();
            params.put("lastQueryTimestamp", mLastSyncTimestamp);

            // request basket
            mInterface.request(mHandshake, "playerUndecorated/getInventory", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intGetObjectsInCells(final S2LatLngRect region, final Handler handler) {
        try {
            checkInterface();

            // get cell ids for surrounding area
            String cellIds[] = Utils.getCellIdsFromRegion(region, 16, 16);

            // create cells
            JSONArray cellsAsHex = new JSONArray();
            for (int i = 0; i < cellIds.length; i++)
                cellsAsHex.put(cellIds[i]);

            // create dates (timestamps?)
            JSONArray dates = new JSONArray();
            for (int i = 0; i < cellsAsHex.length(); i++)
                dates.put(0);

            // create params
            JSONObject params = new JSONObject();
            params.put("cellsAsHex", cellsAsHex);
            params.put("dates", dates);

            // request basket
            mInterface.request(mHandshake, "gameplay/getObjectsInCells", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intLoadCommunication(final double radiusKM, final boolean factionOnly, final Handler handler) {
        try {
            checkInterface();

            final double earthKM = 2 * Math.PI * 6371; // circumference

            S2LatLng center = S2LatLng.fromE6(mLocation.getLatitude(), mLocation.getLongitude());
            S2LatLng size = S2LatLng.fromRadians((Math.PI / earthKM) * radiusKM,
                    (2 * Math.PI / earthKM) * radiusKM);
            S2LatLngRect region = S2LatLngRect.fromCenterSize(center, size);

            // get cell ids for area
            String[] cellIds = Utils.getCellIdsFromRegion(region, 8, 12);

            // create cells
            JSONArray cellsAsHex = new JSONArray();
            for (int i = 0; i < cellIds.length; i++)
                cellsAsHex.put(cellIds[i]);

            // create params
            JSONObject params = new JSONObject();
            params.put("cellsAsHex", cellsAsHex);
            params.put("minTimestampMs", -1);
            params.put("maxTimestampMs", -1);
            params.put("desiredNumItems", 50);
            params.put("factionOnly", factionOnly);
            params.put("ascendingTimestampOrder", false);

            mInterface.request(mHandshake, "playerUndecorated/getPaginatedPlexts", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleResult(JSONArray result) {
                            try {
                                // add plexts
                                for (int i = 0; i < result.length(); i++) {
                                    PlextBase newPlext = PlextBase.createByJSON(result.getJSONArray(i));
                                    mPlexts.add(newPlext);
                                }
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intSendMessage(final String message, final boolean factionOnly, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("message", message);
            params.put("factionOnly", factionOnly);

            mInterface.request(mHandshake, "player/say", mLocation, params, new RequestResult(handler));
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intGetGameScore(final Handler handler) {
        try {
            checkInterface();

            mInterface.request(mHandshake, "playerUndecorated/getGameScore", null, null,
                    new RequestResult(handler) {
                        @Override
                        public void handleResult(JSONObject result) {
                            try {
                                getData().putInt("ResistanceScore", result.getInt("resistanceScore"));
                                getData().putInt("EnlightenedScore", result.getInt("alienScore"));
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intRedeemReward(String passcode, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            JSONArray passcodes = new JSONArray();
            passcodes.put(passcode);
            params.put("params", passcodes);

            mInterface.request(mHandshake, "playerUndecorated/redeemReward", null, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleError(String error) {
                            if (error.equals("INVALID_PASSCODE"))
                                super.handleError("Passcode invalid");
                            else if (error.equals("ALREADY_REDEEMED"))
                                super.handleError("Passcode already redemmed");
                            else if (error.equals("ALREADY_REDEEMED_BY_PLAYER"))
                                super.handleError("Passcode already redemmed by you");
                            else
                                super.handleError("Unknown error: " + error);

                            super.handleError(error);
                        }

                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }
                    });

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void intGetNumberOfInvites(final Handler handler) {
        try {
            checkInterface();

            mInterface.request(mHandshake, "playerUndecorated/getInviteInfo", null, null,
                    new RequestResult(handler) {
                        @Override
                        public void handleResult(JSONObject result) {
                            try {
                                getData().putInt("NumInvites", result.getInt("numAvailableInvites"));
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intInviteUser(final String email, final String customMessage, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            if (customMessage == null)
                params.put("customMessage", "");
            else
                params.put("customMessage", customMessage);
            params.put("inviteeEmailAddress", email);

            mInterface.request(mHandshake, "playerUndecorated/inviteViaEmail", null, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleResult(JSONObject result) {
                            try {
                                getData().putInt("NumInvites", result.getInt("numAvailableInvites"));
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intValidateNickname(final String nickname, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            JSONArray nicknames = new JSONArray();
            nicknames.put(nickname);
            params.put("params", nicknames);

            mInterface.request(mHandshake, "playerUndecorated/validateNickname", null, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleError(String error) {
                            if (error.equals("INVALID_CHARACTERS"))
                                super.handleError("Nickname contains invalid characters");
                            else if (error.equals("TOO_SHORT"))
                                super.handleError("Nickname is too short");
                            else if (error.equals("BAD_WORDS"))
                                super.handleError("Nickname contains bad words");
                            else if (error.equals("NOT_UNIQUE"))
                                super.handleError("Nickname is already in use");
                            else if (error.equals("CANNOT_EDIT"))
                                super.handleError("Cannot edit nickname");
                            else
                                super.handleError("Unknown error: " + error);
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intPersistNickname(final String nickname, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            JSONArray nicknames = new JSONArray();
            nicknames.put(nickname);
            params.put("params", nicknames);

            mInterface.request(mHandshake, "playerUndecorated/persistNickname", null, params,
                    new RequestResult(handler));
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intChooseFaction(final Team team, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            JSONArray factions = new JSONArray();
            factions.put(team.toString());
            params.put("params", factions);

            mInterface.request(mHandshake, "playerUndecorated/chooseFaction", null, params,
                    new RequestResult(handler));
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intGetNicknameFromUserGUID(String guid, final Handler handler) {
        String[] guids = { guid };
        intGetNicknamesFromUserGUIDs(guids, handler);
    }

    public void intGetNicknamesFromUserGUIDs(final String[] guids, final Handler handler) {
        try {
            checkInterface();

            // create params (don't know why there are two nested arrays)
            JSONObject params = new JSONObject();

            JSONArray playerGuids = new JSONArray();
            for (String guid : guids)
                playerGuids.put(guid);

            JSONArray playerIds = new JSONArray();
            playerIds.put(playerGuids);
            params.put("params", playerIds);

            mInterface.request(mHandshake, "playerUndecorated/getNickNamesFromPlayerIds", null, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleResult(JSONArray result) {
                            try {
                                // retrieve nicknames for user ids
                                if (result != null && result.length() > 0) {
                                    for (int i = 0; i < result.length(); i++) {
                                        if (!result.isNull(i))
                                            getData().putString(guids[i], result.getString(i));
                                    }
                                }
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intFireWeapon(ItemWeapon weapon, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("itemGuid", weapon.getEntityGuid());

            mInterface.request(mHandshake, "gameplay/fireUntargetedRadialWeapon", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleError(String error) {
                            // PLAYER_DEPLETED, WEAPON_DOES_NOT_EXIST
                            super.handleError(error);
                        }

                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intHackPortal(GameEntityPortal portal, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("itemGuid", portal.getEntityGuid());

            mInterface.request(mHandshake, "gameplay/collectItemsFromPortal", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleError(String error) {
                            // TOO_SOON_BIG, TOO_SOON_(x), TOO_OFTEN, OUT_OF_RANGE, NEED_MORE_ENERGY, SERVER_ERROR
                            super.handleError(error);
                        }

                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intDeployResonator(ItemResonator resonator, GameEntityPortal portal, int slot,
            final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("portalGuid", portal.getEntityGuid());
            params.put("preferredSlot", slot);

            JSONArray resonators = new JSONArray();
            resonators.put(resonator.getEntityGuid());
            params.put("itemGuids", resonators);

            mInterface.request(mHandshake, "gameplay/deployResonatorV2", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleError(String error) {
                            // PORTAL_OUT_OF_RANGE, TOO_MANY_RESONATORS_FOR_LEVEL_BY_USER, PORTAL_AT_MAX_RESONATORS, ITEM_DOES_NOT_EXIST, SERVER_ERROR
                            super.handleError(error);
                        }

                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intUpgradeResonator(ItemResonator resonator, GameEntityPortal portal, int slot,
            final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("emitterGuid", resonator.getEntityGuid());
            params.put("portalGuid", portal.getEntityGuid());
            params.put("resonatorSlotToUpgrade", slot);

            mInterface.request(mHandshake, "gameplay/upgradeResonatorV2", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleError(String error) {
                            // PORTAL_OUT_OF_RANGE, CAN_ONLY_UPGRADE_TO_HIGHER_LEVEL, TOO_MANY_RESONATORS_FOR_LEVEL_BY_USER
                            super.handleError(error);
                        }

                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intAddMod(ItemMod mod, GameEntityPortal portal, int slot, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("modResourceGuid", mod.getEntityGuid());
            params.put("modableGuid", portal.getEntityGuid());
            params.put("index", slot);

            mInterface.request(mHandshake, "gameplay/addMod", mLocation, params, new RequestResult(handler) {
                @Override
                public void handleError(String error) {
                    // PORTAL_OUT_OF_RANGE, (there must be others)
                    super.handleError(error);
                }

                @Override
                public void handleGameBasket(GameBasket gameBasket) {
                    processGameBasket(gameBasket);
                }
            });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intRemoveMod(GameEntityPortal portal, int slot, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("modableGuid", portal.getEntityGuid());
            params.put("index", slot);

            mInterface.request(mHandshake, "gameplay/removeMod", mLocation, params, new RequestResult(handler) {
                @Override
                public void handleError(String error) {
                    // PORTAL_OUT_OF_RANGE, (there must be others)
                    super.handleError(error);
                }

                @Override
                public void handleGameBasket(GameBasket gameBasket) {
                    processGameBasket(gameBasket);
                }
            });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intDropItem(ItemBase item, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("itemGuid", item.getEntityGuid());

            mInterface.request(mHandshake, "gameplay/dropItem", mLocation, params, new RequestResult(handler) {
                @Override
                public void handleGameBasket(GameBasket gameBasket) {
                    processGameBasket(gameBasket);
                }
            });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intPickupItem(String guid, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("itemGuid", guid);

            mInterface.request(mHandshake, "gameplay/pickUp", mLocation, params, new RequestResult(handler) {
                @Override
                public void handleError(String error) {
                    // RESOURCE_NOT_AVAILABLE
                    super.handleError(error);
                }

                @Override
                public void handleGameBasket(GameBasket gameBasket) {
                    processGameBasket(gameBasket);
                }
            });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intRecycleItem(ItemBase item, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("itemGuid", item.getEntityGuid());

            mInterface.request(mHandshake, "gameplay/recycleItem", mLocation, params, new RequestResult(handler) {
                @Override
                public void handleError(String error) {
                    // DOES_NOT_EXIST
                    super.handleError(error);
                }

                @Override
                public void handleGameBasket(GameBasket gameBasket) {
                    processGameBasket(gameBasket);
                }

                @Override
                public void handleResult(String result) {
                    // TODO: result contains the gained xm value, put into msg
                }
            });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intUsePowerCube(ItemPowerCube powerCube, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("itemGuid", powerCube.getEntityGuid());

            mInterface.request(mHandshake, "gameplay/dischargePowerCube", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }

                        @Override
                        public void handleResult(String result) {
                            // TODO: result contains the gained xm value, put into msg
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intRechargePortal(GameEntityPortal portal, int[] slots, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("portalGuid", portal.getEntityGuid());

            JSONArray resonatorSlots = new JSONArray();
            for (int slot : slots) {
                resonatorSlots.put(slot);
            }
            params.put("resonatorSlots", resonatorSlots);

            mInterface.request(mHandshake, "gameplay/rechargeResonatorsV2", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intRemoteRechargePortal(GameEntityPortal portal, ItemPortalKey key, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("portalGuid", portal.getEntityGuid());
            params.put("portalKeyGuid", key.getEntityGuid());

            JSONArray resonatorSlots = new JSONArray();
            for (int i = 0; i < 8; i++)
                resonatorSlots.put(i);
            params.put("resonatorSlots", resonatorSlots);

            mInterface.request(mHandshake, "gameplay/remoteRechargeResonatorsV2", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleGameBasket(GameBasket gameBasket) {
                            processGameBasket(gameBasket);
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intQueryLinkablilityForPortal(GameEntityPortal portal, ItemPortalKey key, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("originPortalGuid", portal.getEntityGuid());

            JSONArray queryForPortals = new JSONArray();
            queryForPortals.put(key.getEntityGuid());
            params.put("portalLinkKeyGuidSet", queryForPortals);

            mInterface.request(mHandshake, "gameplay/getLinkabilityImpediment", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleResult(JSONObject result) {
                            // TODO: don't know the result yet
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intLinkPortal(GameEntityPortal portal, ItemPortalKey toKey, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("originPortalGuid", portal.getEntityGuid());
            params.put("destinationPortalGuid", toKey.getPortalGuid());
            params.put("linkKeyGuid", toKey.getEntityGuid());

            mInterface.request(mHandshake, "gameplay/createLink", mLocation, params, new RequestResult(handler) {
                @Override
                public void handleGameBasket(GameBasket gameBasket) {
                    processGameBasket(gameBasket);
                }
            });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intSetNotificationSettings(final Handler handler) {
        Log.w("Game", "intSetNotificationSettings not yet implemented");
    }

    public void intGetModifiedEntity(final Handler handler) {
        Log.w("Game", "intSetNotificationSettings not yet implemented");
    }

    public void intFlipPortal(GameEntityPortal portal, ItemFlipCard flipCard, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("portalGuid", portal.getEntityGuid());
            params.put("resourceGuid", flipCard.getEntityGuid());

            mInterface.request(mHandshake, "gameplay/flipPortal", mLocation, params, new RequestResult(handler) {
                @Override
                public void handleGameBasket(GameBasket gameBasket) {
                    processGameBasket(gameBasket);
                }
            });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intSetPortalDetailsForCuration(final Handler handler) {
        Log.w("Game", "intSetPortalDetailsForCuration not yet implemented");
    }

    public void intGetUploadUrl(final Handler handler) {
        try {
            checkInterface();

            mInterface.request(mHandshake, "playerUndecorated/getUploadUrl", null, null,
                    new RequestResult(handler) {
                        @Override
                        public void handleResult(String result) {
                            getData().putString("Url", result);
                        }
                    });
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void intUploadPortalPhotoByUrl(String requestId, String imageUrl, final Handler handler) {
        Log.w("Game", "intUploadPortalPhotoByUrl not yet implemented");
    }

    public void intUploadPortalImage(final Handler handler) {
        Log.w("Game", "intUploadPortalImage not yet implemented");
    }

    public void intFindNearbyPortals(int maxPortals, final Handler handler) {
        try {
            checkInterface();

            JSONObject params = new JSONObject();
            params.put("maxPortals", maxPortals);

            mInterface.request(mHandshake, "gameplay/findNearbyPortals", mLocation, params,
                    new RequestResult(handler) {
                        @Override
                        public void handleResult(JSONArray result) {
                            // TODO: UNDONE
                        }
                    });
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public Handshake getHandshake() {
        return mHandshake;
    }

    public KnobsBundle getKnobs() {
        return mKnobs;
    }

    public synchronized World getWorld() {
        return mWorld;
    }

    public synchronized Inventory getInventory() {
        return mInventory;
    }

    public synchronized Agent getAgent() {
        checkInterface();
        return mAgent;
    }

    public synchronized List<PlextBase> getPlexts() {
        return mPlexts;
    }
}