Multithread Market Saving + Record History for Markets

This commit is contained in:
Kam committed 2024-02-20 20:29:49 -05:00
1 parent 9e7c2d7e6a
commit 3507cb85c5
13 files changed
+172 -74

No files matched your search

+57 -15
View File
@@ -9,6 +9,8 @@ import noppes.npcs.LogWriter;
import noppes.npcs.config.ConfigMain;
import noppes.npcs.entity.EntityNPCInterface;
import noppes.npcs.roles.RoleTrader;
import noppes.npcs.util.CacheHashMap;
import noppes.npcs.util.MarketCachedObject;
import noppes.npcs.util.NBTJsonUtil;
import java.io.File;
@@ -16,28 +18,68 @@ import java.io.FileOutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static noppes.npcs.controllers.PlayerDataController.loadNBTData;
import static noppes.npcs.util.CustomNPCsThreader.customNPCThread;
public class Market {
static public void save(RoleTrader r, String name) {
private static final CacheHashMap<String, MarketCachedObject> marketCache = new CacheHashMap<>(5 * 60 * 1000, 1 * 60 * 1000);
public static void save(RoleTrader r, String name) {
if(name.isEmpty())
return;
NBTTagCompound roleCompound = r.writeNBT(new NBTTagCompound());
roleCompound.setString("SaveName", name);
putMarketCache(name, roleCompound);
if(r.recordHistory)
return;
saveFile(roleCompound);
}
public static void saveFile(NBTTagCompound compound) {
String name = compound.getString("SaveName");
File file = getFile(name + "_new");
File file1 = getFile(name);
customNPCThread.execute(() -> {
try {
if(ConfigMain.MarketDatFormat){
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(file));
} else {
NBTJsonUtil.SaveFile(file, compound);
}
if(file1.exists()){
file1.delete();
}
file.renameTo(file1);
} catch (Exception e) {
try {
if(ConfigMain.MarketDatFormat){
CompressedStreamTools.writeCompressed(r.writeNBT(new NBTTagCompound()), new FileOutputStream(file));
} else {
NBTJsonUtil.SaveFile(file, r.writeNBT(new NBTTagCompound()));
}
if(file1.exists()){
file1.delete();
}
file.renameTo(file1);
} catch (Exception e) {
});
}
public static void getMarket(RoleTrader role, String name){
NBTTagCompound data = getMarketCache(name);
if(data != null){
role.readNBT(data);
return;
}
load(role, name);
}
public static NBTTagCompound getMarketCache(final String name) {
synchronized (marketCache) {
if (!marketCache.containsKey(name)) {
return null;
}
return marketCache.get(name).getObject();
}
}
public static void putMarketCache(final String name, final NBTTagCompound role) {
synchronized (marketCache) {
marketCache.put(name, new MarketCachedObject(role));
}
}
@@ -51,7 +93,7 @@ public class Market {
try {
if(ConfigMain.MarketDatFormat){
NBTTagCompound compound = loadNBTData(file);
NBTTagCompound compound = NBTJsonUtil.loadNBTData(file);
role.readNBT(compound);
}
else {
@@ -106,7 +148,7 @@ public class Market {
if(!getFile(marketName).exists())
Market.save((RoleTrader) npc.roleInterface, marketName);
Market.load((RoleTrader) npc.roleInterface, marketName);
Market.getMarket((RoleTrader) npc.roleInterface, marketName);
}
@@ -164,7 +206,7 @@ public class Market {
}
} else {
if(file.getName().endsWith(".dat")){
compound = loadNBTData(file);
compound = NBTJsonUtil.loadNBTData(file);
if(compound.hasKey("PlayerName")){
filename = file.getName().substring(0, file.getName().length() - 4);
valid = true;
@@ -1094,6 +1094,8 @@ public class PacketHandlerServer{
}
else if(type == EnumPacketServer.TraderMarketSave){
String market = Server.readString(buffer);
if(market == null)
return;
boolean bo = buffer.readBoolean();
if(npc.roleInterface instanceof RoleTrader){
if(bo)
@@ -14,17 +14,17 @@ import noppes.npcs.roles.RoleTrader;
import org.lwjgl.opengl.GL11;
public class GuiNpcTraderSetup extends GuiContainerNPCInterface2 implements ITextfieldListener{
private final ResourceLocation slot = new ResourceLocation("customnpcs","textures/gui/slot.png");
private RoleTrader role;
public GuiNpcTraderSetup(EntityNPCInterface npc, ContainerNPCTraderSetup container){
super(npc, container);
ySize = 220;
menuYOffset = 10;
role = container.role;
}
@Override
public void initGui(){
super.initGui();
@@ -35,9 +35,12 @@ public class GuiNpcTraderSetup extends GuiContainerNPCInterface2 implements ITex
addLabel(new GuiNpcLabel(1, "gui.ignoreDamage", guiLeft + 260, guiTop + 29));
addButton(new GuiNpcButtonYesNo(1, guiLeft + 340, guiTop + 24, role.ignoreDamage));
addLabel(new GuiNpcLabel(2, "gui.ignoreNBT", guiLeft + 260, guiTop + 51));
addButton(new GuiNpcButtonYesNo(2, guiLeft + 340, guiTop + 46, role.ignoreNBT));
addLabel(new GuiNpcLabel(3, "gui.recordHistory", guiLeft + 260, guiTop + 73));
addButton(new GuiNpcButtonYesNo(3, guiLeft + 340, guiTop + 68, role.recordHistory));
}
@Override
@@ -55,6 +58,9 @@ public class GuiNpcTraderSetup extends GuiContainerNPCInterface2 implements ITex
if(guibutton.id == 2){
role.ignoreNBT = ((GuiNpcButtonYesNo)guibutton).getBoolean();
}
if(guibutton.id == 3){
role.recordHistory = ((GuiNpcButtonYesNo)guibutton).getBoolean();
}
}
@Override
@@ -69,20 +75,20 @@ public class GuiNpcTraderSetup extends GuiContainerNPCInterface2 implements ITex
GL11.glColor4f(1, 1, 1, 1);
drawTexturedModalRect(x - 1, y, 0, 0, 18, 18);
drawTexturedModalRect(x + 17, y, 0, 0, 18, 18);
fontRendererObj.drawString("=", x + 36, y + 5, CustomNpcResourceListener.DefaultTextColor);
mc.renderEngine.bindTexture(this.slot);
GL11.glColor4f(1, 1, 1, 1);
drawTexturedModalRect(x + 42, y, 0, 0, 18, 18);
}
}
@Override
public void save() {
Client.sendData(EnumPacketServer.TraderMarketSave, role.marketName, false);
Client.sendData(EnumPacketServer.RoleSave, role.writeToNBT(new NBTTagCompound()));
}
@Override
public void unFocused(GuiNpcTextField guiNpcTextField) {
String name = guiNpcTextField.getText();
@@ -90,6 +96,6 @@ public class GuiNpcTraderSetup extends GuiContainerNPCInterface2 implements ITex
role.marketName = name;
Client.sendData(EnumPacketServer.TraderMarketSave, role.marketName, true);
}
}
}
@@ -28,7 +28,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.zip.GZIPInputStream;
import static noppes.npcs.util.CustomNPCsThreader.playerDataThread;
import static noppes.npcs.util.CustomNPCsThreader.customNPCThread;
public class PlayerDataController {
public static PlayerDataController Instance;
@@ -66,7 +66,7 @@ public class PlayerDataController {
}
}
if(file.getName().endsWith(".dat")){
NBTTagCompound compound = loadNBTData(file);
NBTTagCompound compound = NBTJsonUtil.loadNBTData(file);
if(compound.hasKey("PlayerName")){
map.put(compound.getString("PlayerName"), file.getName().substring(0, file.getName().length() - 4));
}
@@ -128,7 +128,7 @@ public class PlayerDataController {
}
public synchronized void savePlayerDataMap(){
playerDataThread.execute(() -> {
customNPCThread.execute(() -> {
try {
File saveDir = CustomNpcs.getWorldSaveDirectory();
File file = new File(saveDir, "playerdatamap.dat_new");
@@ -230,7 +230,7 @@ public class PlayerDataController {
File file = new File(saveDir, filename);
if(file.exists()){
if(ConfigMain.DatFormat){
return loadNBTData(file);
return NBTJsonUtil.loadNBTData(file);
} else {
return NBTJsonUtil.LoadFile(file);
}
@@ -242,16 +242,7 @@ public class PlayerDataController {
return new NBTTagCompound();
}
public static NBTTagCompound loadNBTData(File file){
try {
return CompressedStreamTools.readCompressed(new FileInputStream(file));
} catch (Exception e) {
LogWriter.error("Error loading: " + file.getName(), e);
}
return new NBTTagCompound();
}
public void putPlayerDataCache(final String uuid, final PlayerData playerCompound) {
public void putPlayerDataCache(final String uuid, final PlayerData playerCompound) {
synchronized (playerDataCache) {
playerDataCache.put(uuid, new CacheHashMap.CachedObject<>(playerCompound));
}
@@ -453,7 +444,7 @@ public class PlayerDataController {
}
}
if(file.getName().endsWith(".dat")){
NBTTagCompound compound = loadNBTData(file);
NBTTagCompound compound = NBTJsonUtil.loadNBTData(file);
if(compound.hasKey("PlayerName")){
map.put(compound.getString("PlayerName"), file.getName().substring(0, file.getName().length() - 4));
}
@@ -536,7 +527,7 @@ public class PlayerDataController {
}
} else {
if(file.getName().endsWith(".dat")){
compound = loadNBTData(file);
compound = NBTJsonUtil.loadNBTData(file);
if(compound.hasKey("PlayerName")){
filename = file.getName().substring(0, file.getName().length() - 4);
valid = true;
@@ -277,7 +277,7 @@ public class PlayerData implements IExtendedEntityProperties, IPlayerData {
}
PlayerDataController.Instance.putPlayerMap(playername, uuid);
PlayerDataController.Instance.putPlayerDataCache(uuid, this);
CustomNPCsThreader.playerDataThread.execute(() -> {
CustomNPCsThreader.customNPCThread.execute(() -> {
try {
File saveDir = PlayerDataController.Instance.getSaveDir();
File file = new File(saveDir, filename + "_new");
+26 -23
View File
@@ -15,7 +15,7 @@ import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RoleTrader extends RoleInterface{
public class RoleTrader extends RoleInterface {
public String marketName = "";
public NpcMiscInventory inventoryCurrency;
@@ -23,14 +23,13 @@ public class RoleTrader extends RoleInterface{
public boolean ignoreDamage = false;
public boolean ignoreNBT = false;
public boolean toSave = false;
public boolean recordHistory = false;
public int[] purchases;
public int[] disableSlot;
public HashMap<String, int[]> playerPurchases;
public HashMap<String, int[]> playerDisableSlot;
public RoleTrader(EntityNPCInterface npc) {
super(npc);
inventoryCurrency = new NpcMiscInventory(36);
@@ -45,10 +44,6 @@ public class RoleTrader extends RoleInterface{
public NBTTagCompound writeToNBT(NBTTagCompound nbttagcompound) {
nbttagcompound.setString("TraderMarket", marketName);
writeNBT(nbttagcompound);
if (toSave && !npc.isRemote()) {
Market.save(this, marketName);
}
toSave = false;
return nbttagcompound;
}
@@ -57,10 +52,13 @@ public class RoleTrader extends RoleInterface{
nbttagcompound.setTag("TraderSold", inventorySold.getToNBT());
nbttagcompound.setBoolean("TraderIgnoreDamage", ignoreDamage);
nbttagcompound.setBoolean("TraderIgnoreNBT", ignoreNBT);
nbttagcompound.setIntArray("Purchases", purchases);
nbttagcompound.setBoolean("RecordHistory", recordHistory);
nbttagcompound.setIntArray("DisableSlot", disableSlot);
nbttagcompound.setTag("PlayerPurchases", NBTTags.nbtStringIntegerArrayMap(playerPurchases));
nbttagcompound.setTag("PlayerDisableSlot", NBTTags.nbtStringIntegerArrayMap(playerDisableSlot));
if(recordHistory){
nbttagcompound.setIntArray("Purchases", purchases);
nbttagcompound.setTag("PlayerPurchases", NBTTags.nbtStringIntegerArrayMap(playerPurchases));
}
return nbttagcompound;
}
@@ -68,12 +66,11 @@ public class RoleTrader extends RoleInterface{
public void readFromNBT(NBTTagCompound nbttagcompound) {
marketName = nbttagcompound.getString("TraderMarket");
readNBT(nbttagcompound);
try {
Market.load(this, marketName);
Market.getMarket(this, marketName);
} catch (Exception ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
}
}
@@ -82,25 +79,28 @@ public class RoleTrader extends RoleInterface{
inventorySold.setFromNBT(nbttagcompound.getCompoundTag("TraderSold"));
ignoreDamage = nbttagcompound.getBoolean("TraderIgnoreDamage");
ignoreNBT = nbttagcompound.getBoolean("TraderIgnoreNBT");
purchases = nbttagcompound.getIntArray("Purchases");
recordHistory = nbttagcompound.getBoolean("RecordHistory");
disableSlot = nbttagcompound.getIntArray("DisableSlot");
playerDisableSlot = NBTTags.getStringIntegerArrayMap(nbttagcompound.getTagList("PlayerDisableSlot", 10), 18);
if(recordHistory){
purchases = nbttagcompound.getIntArray("Purchases");
playerPurchases = NBTTags.getStringIntegerArrayMap(nbttagcompound.getTagList("PlayerPurchases", 10), 18);
}
if (purchases == null || purchases.length != 18) {
purchases = new int[18];
for (int i = 0; i < purchases.length; ++i) purchases[i] = 0;
}
disableSlot = nbttagcompound.getIntArray("DisableSlot");
if (disableSlot == null || disableSlot.length != 18) {
disableSlot = new int[18];
for (int i = 0; i < disableSlot.length; ++i) disableSlot[i] = 0;
}
playerPurchases = NBTTags.getStringIntegerArrayMap(nbttagcompound.getTagList("PlayerPurchases", 10), 18);
playerDisableSlot = NBTTags.getStringIntegerArrayMap(nbttagcompound.getTagList("PlayerDisableSlot", 10), 18);
}
@Override
public void interact(EntityPlayer player) {
npc.say(player, npc.advanced.getInteractLine());
try {
Market.load(this, marketName);
Market.getMarket(this, marketName);
} catch (Exception ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
}
@@ -117,19 +117,22 @@ public class RoleTrader extends RoleInterface{
}
return false;
}
public void addPurchase(int slot, String playerName) {
if(slot >= 18 || slot < 0) return;
++purchases[slot];
++getArrayByName(playerName, playerPurchases)[slot];
if(recordHistory)
Market.save(this, marketName);
}
public boolean isSlotEnabled(int slot, String playerName) {
if(slot >= 18 || slot < 0) return false;
if (disableSlot[slot] > 0) return false;
return getArrayByName(playerName, playerDisableSlot)[slot] <= 0;
}
public int[] getArrayByName(String name, HashMap<String, int[]> map) {
map.computeIfAbsent(name, k -> new int[18]);
return map.get(name);
@@ -30,7 +30,7 @@ public class ScriptRoleTrader extends ScriptRoleInterface implements IRoleTrader
role.inventoryCurrency.items.put(slot + 18, currency2.getMCItemStack());
else
role.inventoryCurrency.items.remove(slot + 18);
role.inventorySold.items.put(slot, sold.getMCItemStack());
}
@@ -55,7 +55,7 @@ public class ScriptRoleTrader extends ScriptRoleInterface implements IRoleTrader
}
return currency;
}
public void removeSellOption(int slot){
if(slot >= 18 || slot < 0) return;
@@ -66,7 +66,7 @@ public class ScriptRoleTrader extends ScriptRoleInterface implements IRoleTrader
public void setMarket(String name){
role.marketName = name;
Market.load(role, name);
Market.getMarket(role, name);
}
public String getMarket(){
@@ -6,11 +6,17 @@ import java.util.Map;
public class CacheHashMap<K, V extends CacheHashMap.CachedObject<?>> extends HashMap<K, V> {
private final long maxCacheTime;
private long saveInterval;
public CacheHashMap(long maxCacheTime) {
this.maxCacheTime = maxCacheTime;
}
public CacheHashMap(long maxCacheTime, long saveInterval) {
this.maxCacheTime = maxCacheTime;
this.saveInterval = saveInterval;
}
@Override
public V get(Object key) {
V object = super.get(key);
@@ -19,9 +25,16 @@ public class CacheHashMap<K, V extends CacheHashMap.CachedObject<?>> extends Has
Iterator<Map.Entry<K,V>> iterator = this.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<K,V> entry = iterator.next();
long timeDiff = entry.getValue().timeSinceAccessed();
if (timeDiff > this.maxCacheTime) {
long lifeTimeDiff = entry.getValue().timeSinceAccessed();
if (lifeTimeDiff > this.maxCacheTime) {
entry.getValue().save();
iterator.remove();
} else if (this.saveInterval > 0) {
long saveTimeDiff = entry.getValue().timeSinceSaved();
if (saveTimeDiff > this.saveInterval) {
entry.getValue().save();
entry.getValue().updateSaveTime();
}
}
}
@@ -29,22 +42,34 @@ public class CacheHashMap<K, V extends CacheHashMap.CachedObject<?>> extends Has
}
public static class CachedObject<T> {
private long timeSaved;
private long lastTimeAccessed;
private final T object;
public CachedObject(T object) {
this.object = object;
this.lastTimeAccessed = System.currentTimeMillis();
this.timeSaved = System.currentTimeMillis();
}
public long timeSinceAccessed() {
return System.currentTimeMillis() - this.lastTimeAccessed;
}
public long timeSinceSaved() {
return System.currentTimeMillis() - this.timeSaved;
}
public void updateTimeAccessed() {
this.lastTimeAccessed = System.currentTimeMillis();
}
public void updateSaveTime() {
this.timeSaved = System.currentTimeMillis();
}
public void save(){}
public T getObject() {
return this.object;
}
@@ -2,7 +2,8 @@ package noppes.npcs.util;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class CustomNPCsThreader {
public static final Executor playerDataThread = Executors.newSingleThreadExecutor();
public static final Executor customNPCThread = Executors.newSingleThreadExecutor();
}
@@ -0,0 +1,15 @@
package noppes.npcs.util;
import foxz.utils.Market;
import net.minecraft.nbt.NBTTagCompound;
public class MarketCachedObject extends CacheHashMap.CachedObject<NBTTagCompound> {
public MarketCachedObject(NBTTagCompound object) {
super(object);
}
@Override
public void save() {
Market.saveFile(getObject());
}
}
@@ -3,12 +3,10 @@ package noppes.npcs.util;
import com.google.common.io.Files;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
import net.minecraft.nbt.*;
import noppes.npcs.LogWriter;
import org.apache.commons.io.Charsets;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
@@ -211,7 +209,17 @@ public class NBTJsonUtil {
}
return json;
}
static class JsonLine{
public static NBTTagCompound loadNBTData(File file){
try {
return CompressedStreamTools.readCompressed(new FileInputStream(file));
} catch (Exception e) {
LogWriter.error("Error loading: " + file.getName(), e);
}
return new NBTTagCompound();
}
static class JsonLine{
private String line;
public JsonLine(String line){
this.line = line;