package Pedestal import initlater InstantBuild import public PedestalObjects import Assets import BaseObject import HashMap import PlayerData import Builder import JsonParser import TileData import LZW import StringUtils import SaveLoadData import ItemObject import HashList constant CHAR_STEPSIZE = 180 public class MemoryAccessPedestal extends StaticBaseObject static constant ENTITIES_KEY = "e" static constant TILES_KEY = "t" static MemoryAccessPedestal array lastRef private constant tileMap = new HashMap() private var entities = new HashList() private var tiles = new LinkedList() private var effects = new HashMap() private var syncingDone = true private var ttag = createFText(pos, "", 12) let bs = new BigString() let parser = new JsonParser() let listparser = new JsonParser() construct(vec2 pos, player owner) super(pos, createUnit(owner, PED_ID, pos, angle(bj_UNIT_FACING)), 0, null, null) setPos(pos.toTile().toVec3()) ttag.tt.center(pos.toVec3(), "|cff4AA542ready", 10) actor..addAbility(SAVE1_ID)..addAbility(LOAD1_ID)..addAbility(SAVE2_ID)..addAbility(SAVE3_ID) ..addAbility(SELECT_TILE_ID)..addAbility(LOAD2_ID)..addAbility(SELECT_AOE_TILE_ID) ..addAbility(LOAD3_ID)..addAbility(REMOVE_OBJECT_ID)..addAbility(SELECT_SINGLE_ID)..addAbility(SELECT_AOE_ID) clearQuestionmark() function addObj(Entity serializable, boolean removeIfExists) if serializable instanceof Escaper or serializable instanceof Builder or serializable instanceof MemoryAccessPedestal return if getRegionData(serializable.getPos()).canBuild(owner) if entities.has(serializable) if removeIfExists entities.remove(serializable) return // Isnt added yet entities.add(serializable) flashEffect(Abilities.healTarget, serializable.getPos()) if serializable instanceof ItemObject let io = serializable castTo ItemObject effects.put(serializable, io.setup.actor.addEffect(Abilities.innerFireTarget, "overhead")) else if serializable instanceof StaticSetupObject let so = serializable castTo StaticSetupObject effects.put(serializable, so.setup.addEffect(Abilities.innerFireTarget, "overhead")) else if serializable instanceof UnitEntity let ue = serializable castTo UnitEntity effects.put(serializable, ue.actor.addEffect(Abilities.innerFireTarget, "overhead")) function addTile(vec2 tpos, boolean _removeIfExists) let targPos = tpos.toTile() if getRegionData(targPos).canBuild(owner) let mtile = targPos.getEBRTile() if not tileMap.has(mtile.key) if getTileFromType(targPos) != Tile.UNWALKABLE let tdata = new TileData(targPos, mtile.x, mtile.y, owner) tiles.add(tdata) tileMap.put(mtile.key, tdata) function loadSlot(int slotId) nullTimer() -> actor.pause() ttag.tt..center(pos, "|cff0884CEloading...", 10) lastRef[owner.getId()] = this let pd = pData[owner.getId()] pd.p.loadData("EBR\\savedata\\dataSlot" + slotId.toString() + ".pld") (status, data) -> switch status case SUCCESS printLog(Loglevel.DEBUG, "synced") let ref = lastRef[pd.id] ref.ttag.tt..center(ref.pos, "|cff0884CEdecompressing...", 10) ref.syncingDone = true let compressedString = new BigString() for i = 0 to data.getChunkCount() compressedString.addString(data.getChunk(i)) destroy data printLog(Loglevel.DEBUG, "Reconstructed") compressedString.debugPrint() serializeOrigin = ref.pos.toVec2().toTile().toVec3() decompress(compressedString, (PayloadCallback cb1) -> begin printLog(Loglevel.DEBUG, "on finish decompress") ref.parser.setInput(cb1.customData castTo BigString) ref.parser.parse((PayloadCallback cb2) -> begin printLog(Loglevel.DEBUG, "on finish parse") if(ref.parser.output.hasKey(ENTITIES_KEY)) ref.parser.output.getStringList(ENTITIES_KEY, ref.listparser) cb3 -> ref.loadEntities(ref.listparser.outputList) else if(ref.parser.output.hasKey(TILES_KEY)) ref.parser.output.getStringList(TILES_KEY, ref.listparser) cb -> printLog(Loglevel.DEBUG, "load tiles1") ref.loadTiles((cb.customData castTo JsonParser).outputList) end) end) default Log.error("ERROR: " + (status castTo int).toString()) LLIterator itr function loadEntities(LinkedList list) // load entities ttag.tt..center(pos, "|cff0884CEloading Entities...", 10) itr = list.staticItr() PayloadCallback pcb = (PayloadCallback cb) -> begin if itr.hasNext() bs.reset() let next = itr.next() next.next = null listparser.setInput(bs..addSubString(next)) listparser.parse((PayloadCallback cb2) -> begin let json = listparser.output let npos = vec2(json.getReal(KEY_X), json.getReal(KEY_Y)) let tId = json.getInt(KEY_TYPE) let obj = newObjectFromId(owner, serializeOrigin.toVec2() + npos, tId) if obj != null and obj.typeId > 0 obj.deserialize(listparser.output) else Log.debug("couldn't fine serializable type") listparser.output.reset() cb.doStep() end) else ttag.tt..center(pos, "|cff0884CEEntites loaded!", 10) printLog(Loglevel.DEBUG, "entities loaded") doAfter(0.5, () -> begin if parser.output.hasKey(TILES_KEY) parser.output.getStringList(TILES_KEY, listparser, (PayloadCallback cb) -> begin printLog(Loglevel.DEBUG, "load tiles1") loadTiles((cb.customData castTo JsonParser).outputList) end) else printLog(Loglevel.DEBUG, "load finished") ttag.tt..center(pos, "|cffFFBD21load finished!", 10) actor.unpause() end) end pcb.doStep() function loadTiles(LinkedList list) printLog(Loglevel.DEBUG, "load tiles2") ttag.tt..center(pos, "|cff0884CEloading Tiles...", 10) let td = new TileData() let bs = new BigString() td.owner = owner let itr = list.staticItr() PayloadCallback pcb = (PayloadCallback cb1) -> begin var continue = true printLog(Loglevel.DEBUG, "doSeq loadTiles") if itr.hasNext() bs.reset() let next = itr.next() next.next = null printLog(Loglevel.DEBUG, "doSeq loadTiles1: " + next.getCombined()) parser.setInput(bs..addSubString(next)) parser.parse((PayloadCallback cb2) -> begin printLog(Loglevel.DEBUG, "doSeq loadTile2s") td..deserialize(parser.output) parser.output.reset() cb1.doStep() end) else continue = false printLog(Loglevel.DEBUG, "load finished") ttag.tt..center(pos, "|cffFFBD21load finished!", 10) destroy td actor.unpause() return continue end pcb.doStep() BigString tileString = new BigString() BigString entString = new BigString() int currentSlotId function saveSlot(int slotId) Log.debug("Save slot " + slotId.toString()) nullTimer(() -> begin actor..abortOrder()..pause() ttag.tt..center(pos, "|cff0884CEsaving...", 10) serializeOrigin = pos.toVec2().toTile().toVec3() let itr = entities.iterator() currentSlotId = slotId entString.reset() entString.addString(JSON_OPEN_ARRAY.token) doSeq((SeqCallback cb) -> begin var continue = true if itr.hasNext() let next = itr.next() if isValid(next) let json = next.serialize() json.addToBigString(entString) destroy json if itr.hasNext() entString.addString(JSON_SIGN_COMMA.token) effects.get(next).destr() effects.remove(next) itr.remove() else continue = false entString.addString(JSON_CLOSE_ARRAY.token) Log.debug("Save tiles") saveTileSeq() return continue end) end) function isValid(Serializable next) returns boolean return next.typeId > 0 and (not (next instanceof Entity)) or (next instanceof UnitEntity and ((next castTo UnitEntity).actor.isAlive())) function saveTileSeq() Log.debug("Save tiles seq") ttag.tt..center(pos, "|cff0884CEsaving tiles...", 10) tileString.reset() tileString.addString(JSON_OPEN_ARRAY.token) let itr = tiles.staticItr() doSeq((SeqCallback cb) -> begin var continue = true if itr.hasNext() itr.next().serialize().addToBigString(tileString) if itr.hasNext() tileString.addString(JSON_SIGN_COMMA.token) destroy itr.remove() else continue = false tileString.addString(JSON_CLOSE_ARRAY.token) tileString.debugPrint() Log.debug("Saved tiles seq") saveFile() return continue end) function saveFile() Log.debug("Save file") ttag.tt..center(pos, "|cff0884CEpreparing...", 10) let json = new Json() let big = new BigString() json.addProperty(new Property(new BigSubString(ENTITIES_KEY), entString.asSubstring())) json.addProperty(new Property(new BigSubString(TILES_KEY), tileString.asSubstring())) json.addToBigString(big) destroy json ttag.tt..center(pos, "|cff0884CEcompressing...", 10) printLog(Loglevel.DEBUG, "start compress") compress(big) cb -> let compressedData = cb.customData castTo BigString let cstring = new ChunkedString() for i = 0 to (compressedData.getLength() div BIG_SUBSTRING_LEN) let remain = min(BIG_SUBSTRING_LEN, compressedData.getLength() - i * BIG_SUBSTRING_LEN) cstring.append(compressedData.getString(i * BIG_SUBSTRING_LEN, remain)) owner.saveData("EBR\\savedata\\dataSlot" + currentSlotId.toString() + ".pld", cstring) destroy cstring ttag.tt..center(pos, "|cffFFBD21save finished!", 10) destroy big tileMap.flush() actor.unpause() override function onCast() super.onCast() let id = GetSpellAbilityId() let tpos = EventData.getSpellTargetPos() switch id case SELECT_AOE_ID forUnitsInRange(tpos, AOE_PICK_RANGE) u -> if u != actor if u.getEntity() != null let ed = u.getEntity() if ed.owner == owner addObj(ed, false) case SELECT_SINGLE_ID if GetSpellTargetUnit().getEntity().owner == owner addObj(GetSpellTargetUnit().getEntity(), true) case SELECT_TILE_ID addTile(tpos, true) case SAVE1_ID saveSlot(1) case SAVE2_ID saveSlot(2) case SAVE3_ID saveSlot(3) case SAVE4_ID saveSlot(4) case LOAD1_ID loadSlot(1) case LOAD2_ID loadSlot(2) case LOAD3_ID loadSlot(3) case LOAD4_ID loadSlot(4) case SELECT_AOE_TILE_ID let val = (AOE_PICK_RANGE/128.).round() for x = -val to val for y = -val to val addTile((tpos+vec2(x*128.,y*128.)), false) ondestroy for t from tiles.staticItr() destroy t destroy effects destroy entities destroy tiles ttag.recycle() destroy parser destroy listparser