Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vidal committed 2026-03-05 02:36:03 -03:00
commit ddb4072ac1
23 files changed
+62 -201

No files matched your search

@@ -19,56 +19,12 @@ import noppes.npcs.controllers.data.IScriptUnit;
import noppes.npcs.items.ItemNpcTool;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
public class PacketUtil {
// ==================== SCRIPT SESSION TOKEN SYSTEM ====================
// Prevents saving script data before the client has received it from the server.
// Each GET generates a token sent to the client; each SAVE must echo it back.
// Multiple tokens per player are allowed so concurrent script editors don't invalidate each other.
// Tokens are consumed on successful verify to prevent unbounded growth.
private static final int MAX_TOKENS_PER_PLAYER = 10;
private static final Map<UUID, Set<String>> scriptSessionTokens = new ConcurrentHashMap<>();
public static String createScriptSession(EntityPlayerMP player) {
String token = Long.toHexString(ThreadLocalRandom.current().nextLong());
Set<String> tokens = scriptSessionTokens.computeIfAbsent(player.getUniqueID(), k -> new LinkedHashSet<>());
synchronized (tokens) {
// Evict oldest tokens if at capacity
while (tokens.size() >= MAX_TOKENS_PER_PLAYER) {
Iterator<String> it = tokens.iterator();
it.next();
it.remove();
}
tokens.add(token);
}
return token;
}
public static boolean verifyScriptSession(EntityPlayer player, String token) {
if (token == null || token.isEmpty())
return false;
Set<String> tokens = scriptSessionTokens.get(player.getUniqueID());
if (tokens == null)
return false;
synchronized (tokens) {
return tokens.remove(token);
}
}
public static void clearScriptSession(EntityPlayer player) {
scriptSessionTokens.remove(player.getUniqueID());
}
public static boolean verifyItemPacket(String name, EnumItemPacketType type, EntityPlayer player) {
if (player == null)
return false;
@@ -260,14 +216,11 @@ public class PacketUtil {
}
public static void getScripts(IScriptHandler data, EntityPlayerMP player) {
String token = createScriptSession(player);
NBTTagCompound compound = new NBTTagCompound();
compound.setBoolean("ScriptEnabled", data.getEnabled());
compound.setString("ScriptLanguage", data.getLanguage());
compound.setTag("Languages", ScriptController.Instance.nbtLanguages());
compound.setTag("ScriptConsole", NBTTags.NBTLongStringMap(data.getConsoleText()));
compound.setString("ScriptSessionToken", token);
GuiDataPacket.sendGuiData(player, compound);
List<IScriptUnit> containers = data.getScripts();
for (int i = 0; i < containers.size(); i++) {
@@ -284,18 +237,9 @@ public class PacketUtil {
GuiDataPacket.sendGuiData(player, loadComplete);
}
public static boolean saveScripts(IScriptHandler data, ByteBuf buffer, EntityPlayer player) throws IOException {
public static void saveScripts(IScriptHandler data, ByteBuf buffer) throws IOException {
int tab = buffer.readInt();
int totalScripts = buffer.readInt();
NBTTagCompound compound = ByteBufUtils.readNBT(buffer);
// Verify script session token to prevent saving unloaded defaults
String token = compound.getString("ScriptSessionToken");
if (!verifyScriptSession(player, token)) {
LogWriter.error(String.format("Rejected script save from %s: session not verified (data not loaded)", player.getCommandSenderName()));
return false;
}
if (totalScripts == 0) {
data.getScripts().clear();
}
@@ -306,10 +250,12 @@ public class PacketUtil {
} else while (data.getScripts().size() < totalScripts) {
data.getScripts().add(new ScriptContainer(data));
}
NBTTagCompound tabCompound = ByteBufUtils.readNBT(buffer);
// Use factory method to create correct script unit type based on NBT
IScriptUnit script = IScriptUnit.createFromNBT(compound, data);
IScriptUnit script = IScriptUnit.createFromNBT(tabCompound, data);
data.getScripts().set(tab, script);
} else {
NBTTagCompound compound = ByteBufUtils.readNBT(buffer);
data.setLanguage(compound.getString("ScriptLanguage"));
if (!ScriptController.Instance.languages.containsKey(data.getLanguage())) {
if (!ScriptController.Instance.languages.isEmpty()) {
@@ -320,6 +266,5 @@ public class PacketUtil {
}
data.setEnabled(compound.getBoolean("ScriptEnabled"));
}
return true;
}
}
@@ -9,7 +9,6 @@ import kamkeel.npcs.network.PacketClient;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumPlayerPacket;
import kamkeel.npcs.network.packets.data.npc.UpdateNpcPacket;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
@@ -17,16 +16,10 @@ import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.entity.EntityNPCInterface;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class RequestProperSpawnData extends AbstractPacket {
public static final String packetName = "Player|SpawnData";
private static final int BATCH_LIMIT = 5;
private static final Set<Integer> entitiesToFix = new HashSet<>();
private static long lastBatchAttemptMillis = 0L;
private static final long REQUEST_COOLDOWN_MILLIS = 1000L;
private int entityId;
public RequestProperSpawnData() {}
@@ -37,8 +30,7 @@ public class RequestProperSpawnData extends AbstractPacket {
@SideOnly(Side.CLIENT)
public static void clear() {
entitiesToFix.clear();
lastBatchAttemptMillis = 0L;
// No backlog queue to clear.
}
@Override
@@ -81,40 +73,24 @@ public class RequestProperSpawnData extends AbstractPacket {
if (entityID <= 0)
return;
if (npc.clientFixAttempts++ < 3) {
PacketClient.sendClient(new RequestProperSpawnData(entityID));
} else {
entitiesToFix.add(entityID);
}
long now = System.currentTimeMillis();
if (now - npc.clientFixLastRequestMillis < REQUEST_COOLDOWN_MILLIS)
return;
if (npc.clientFixAttempts >= 3)
return;
npc.clientFixLastRequestMillis = now;
npc.clientFixAttempts++;
PacketClient.sendClient(new RequestProperSpawnData(entityID));
}
@SideOnly(Side.CLIENT)
public static boolean canDoBatchUpdate() {
return System.currentTimeMillis() - lastBatchAttemptMillis >= 5000;
return false;
}
@SideOnly(Side.CLIENT)
public static void handleBacklog() {
Minecraft mc = Minecraft.getMinecraft();
if (mc == null || mc.theWorld == null || mc.thePlayer == null)
return;
if (entitiesToFix.isEmpty())
return;
// Remove entity checks if they're no longer loaded
entitiesToFix.removeIf(value -> !(mc.theWorld.getEntityByID(value) instanceof EntityNPCInterface));
Iterator<Integer> it = entitiesToFix.iterator();
int count = 0;
while (it.hasNext() && count < BATCH_LIMIT) {
PacketClient.sendClient(new RequestProperSpawnData(it.next()));
it.remove();
count++;
}
if (count != 0) {
lastBatchAttemptMillis = System.currentTimeMillis();
}
// No batch backlog. Requests are immediate and throttled in reportMissingData().
}
}
@@ -98,7 +98,7 @@ public final class AbilityScriptPacket extends AbstractPacket {
if (requestedAction == Action.GET) {
PacketUtil.getScripts((IScriptHandler) data, (EntityPlayerMP) player);
} else {
data.saveScript(in, player);
data.saveScript(in);
}
return;
}
@@ -107,8 +107,7 @@ public final class AbilityScriptPacket extends AbstractPacket {
if (requestedAction == Action.GET) {
PacketUtil.getScripts((IScriptHandler) data, (EntityPlayerMP) player);
} else {
if (!data.saveScript(in, player))
return;
data.saveScript(in);
// Persist to disk
AbilityController.Instance.saveCustomAbility(ability);
if (ConfigDebug.PlayerLogging && FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) {
@@ -7,7 +7,6 @@ import kamkeel.npcs.network.AbstractPacket;
import kamkeel.npcs.network.PacketChannel;
import kamkeel.npcs.network.PacketClient;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.PacketUtil;
import kamkeel.npcs.network.enums.EnumRequestPacket;
import kamkeel.npcs.network.packets.data.large.GuiDataPacket;
import kamkeel.npcs.util.ByteBufUtils;
@@ -16,7 +15,6 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import noppes.npcs.CustomNpcsPermissions;
import noppes.npcs.LogWriter;
import noppes.npcs.blocks.tiles.TileScripted;
import noppes.npcs.config.ConfigScript;
import noppes.npcs.controllers.ScriptController;
@@ -83,10 +81,8 @@ public final class BlockScriptPacket extends AbstractPacket {
TileEntity tile = player.worldObj.getTileEntity(in.readInt(), in.readInt(), in.readInt());
if (!(tile instanceof TileScripted))
return;
String token = PacketUtil.createScriptSession((EntityPlayerMP) player);
NBTTagCompound compound = ((TileScripted) tile).getNBT(new NBTTagCompound());
compound.setTag("Languages", ScriptController.Instance.nbtLanguages());
compound.setString("ScriptSessionToken", token);
GuiDataPacket.sendGuiData((EntityPlayerMP) player, compound);
NBTTagCompound loadComplete = new NBTTagCompound();
@@ -99,14 +95,8 @@ public final class BlockScriptPacket extends AbstractPacket {
TileEntity tile = player.worldObj.getTileEntity(in.readInt(), in.readInt(), in.readInt());
if (!(tile instanceof TileScripted))
return;
NBTTagCompound compound = ByteBufUtils.readNBT(in);
String token = compound.getString("ScriptSessionToken");
if (!PacketUtil.verifyScriptSession(player, token)) {
LogWriter.error(String.format("Rejected block script save from %s: session not verified", player.getCommandSenderName()));
return;
}
TileScripted script = (TileScripted) tile;
script.setNBT(compound);
script.setNBT(ByteBufUtils.readNBT(in));
script.lastInited = -1;
}
}
@@ -98,7 +98,7 @@ public final class ChainedAbilityScriptPacket extends AbstractPacket {
if (requestedAction == Action.GET) {
PacketUtil.getScripts((IScriptHandler) data, (EntityPlayerMP) player);
} else {
data.saveScript(in, player);
data.saveScript(in);
}
return;
}
@@ -107,8 +107,7 @@ public final class ChainedAbilityScriptPacket extends AbstractPacket {
if (requestedAction == Action.GET) {
PacketUtil.getScripts((IScriptHandler) data, (EntityPlayerMP) player);
} else {
if (!data.saveScript(in, player))
return;
data.saveScript(in);
// Persist to disk
AbilityController.Instance.saveChainedAbility(chain);
if (ConfigDebug.PlayerLogging && FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) {
@@ -90,8 +90,7 @@ public final class EffectScriptPacket extends AbstractPacket {
if (requestedAction == Action.GET) {
PacketUtil.getScripts((IScriptHandler) data, (EntityPlayerMP) player);
} else {
if (!data.saveScript(in, player))
return;
data.saveScript(in);
if (ConfigDebug.PlayerLogging && FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) {
LogWriter.script(String.format("[%s] (Player) %s SAVED EFFECT %s [%s]", "EFFECT SCRIPTS", player.getCommandSenderName(), effect.getName(), effect.id));
}
@@ -89,8 +89,7 @@ public final class EventScriptPacket extends AbstractPacket {
if (requestedAction == Action.GET) {
PacketUtil.getScripts(data, (EntityPlayerMP) player);
} else {
if (!PacketUtil.saveScripts(data, in, player))
return;
PacketUtil.saveScripts(data, in);
npc.updateAI = true;
npc.script.hasInited = false;
if (ConfigDebug.PlayerLogging && FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) {
@@ -84,8 +84,7 @@ public final class ForgeScriptPacket extends AbstractPacket {
PacketUtil.getScripts((IScriptHandler) data, (EntityPlayerMP) player);
} else {
int tab = in.getInt(in.readerIndex());
if (!PacketUtil.saveScripts(data, in, player))
return;
PacketUtil.saveScripts(data, in);
ScriptController.Instance.lastForgeUpdate = System.currentTimeMillis();
if (tab == -1)
ScriptController.Instance.saveForgeScriptsSync();
@@ -84,8 +84,7 @@ public final class GlobalNPCScriptPacket extends AbstractPacket {
PacketUtil.getScripts((IScriptHandler) data, (EntityPlayerMP) player);
} else {
int tab = in.getInt(in.readerIndex());
if (!PacketUtil.saveScripts(data, in, player))
return;
PacketUtil.saveScripts(data, in);
ScriptController.Instance.lastGlobalNpcUpdate = System.currentTimeMillis();
if (tab == -1)
ScriptController.Instance.saveGlobalScriptsSync();
@@ -81,19 +81,11 @@ public final class NPCScriptPacket extends AbstractPacket {
Action requestedAction = Action.values()[in.readInt()];
if (requestedAction == Action.GET) {
String token = PacketUtil.createScriptSession((EntityPlayerMP) player);
NBTTagCompound compound = npc.script.writeToNBT(new NBTTagCompound());
compound.setTag("Languages", ScriptController.Instance.nbtLanguages());
compound.setString("ScriptSessionToken", token);
GuiDataPacket.sendGuiData((EntityPlayerMP) player, compound);
} else {
NBTTagCompound compound = ByteBufUtils.readNBT(in);
String token = compound.getString("ScriptSessionToken");
if (!PacketUtil.verifyScriptSession(player, token)) {
LogWriter.error(String.format("Rejected NPC script save from %s: session not verified", player.getCommandSenderName()));
return;
}
npc.script.readFromNBT(compound);
npc.script.readFromNBT(ByteBufUtils.readNBT(in));
npc.updateAI = true;
npc.script.hasInited = false;
if (ConfigDebug.PlayerLogging && FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) {
@@ -84,8 +84,7 @@ public final class PlayerScriptPacket extends AbstractPacket {
PacketUtil.getScripts((IScriptHandler) data, (EntityPlayerMP) player);
} else {
int tab = in.getInt(in.readerIndex());
if (!PacketUtil.saveScripts(data, in, player))
return;
PacketUtil.saveScripts(data, in);
ScriptController.Instance.lastPlayerUpdate = System.currentTimeMillis();
if (tab == -1)
ScriptController.Instance.savePlayerScriptsSync();
@@ -102,8 +102,7 @@ public final class RecipeScriptPacket extends AbstractPacket {
if (action == Action.GET) {
PacketUtil.getScripts(script, player);
} else {
if (!script.saveScript(in, player))
return;
script.saveScript(in);
if (ConfigDebug.PlayerLogging && FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) {
// TODO: Log Recipe Script Saving
}
@@ -7,7 +7,6 @@ import kamkeel.npcs.network.AbstractPacket;
import kamkeel.npcs.network.PacketChannel;
import kamkeel.npcs.network.PacketClient;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.PacketUtil;
import kamkeel.npcs.network.enums.EnumRequestPacket;
import kamkeel.npcs.network.packets.data.large.GuiDataPacket;
import kamkeel.npcs.util.ByteBufUtils;
@@ -15,7 +14,6 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.CustomNpcsPermissions;
import noppes.npcs.LogWriter;
import noppes.npcs.config.ConfigScript;
import noppes.npcs.controllers.ScriptController;
import noppes.npcs.scripted.NpcAPI;
@@ -74,10 +72,8 @@ public final class ItemScriptPacket extends AbstractPacket {
if (requestedAction == Action.GET) {
ScriptCustomItem iw = (ScriptCustomItem) NpcAPI.Instance().getIItemStack(player.getHeldItem());
iw.loadScriptData();
String token = PacketUtil.createScriptSession((EntityPlayerMP) player);
NBTTagCompound compound = iw.getMCNbt();
compound.setTag("Languages", ScriptController.Instance.nbtLanguages());
compound.setString("ScriptSessionToken", token);
GuiDataPacket.sendGuiData((EntityPlayerMP) player, compound);
NBTTagCompound loadComplete = new NBTTagCompound();
@@ -89,11 +85,6 @@ public final class ItemScriptPacket extends AbstractPacket {
}
NBTTagCompound compound = ByteBufUtils.readNBT(in);
String token = compound.getString("ScriptSessionToken");
if (!PacketUtil.verifyScriptSession(player, token)) {
LogWriter.error(String.format("Rejected item script save from %s: session not verified", player.getCommandSenderName()));
return;
}
ScriptCustomItem wrapper = (ScriptCustomItem) NpcAPI.Instance().getIItemStack(player.getHeldItem());
wrapper.setMCNbt(compound);
wrapper.saveScriptData();
@@ -90,8 +90,7 @@ public final class LinkedItemScriptPacket extends AbstractPacket {
if (requestedAction == Action.GET) {
PacketUtil.getScripts((IScriptHandler) data, (EntityPlayerMP) player);
} else {
if (!data.saveScript(in, player))
return;
data.saveScript(in);
if (ConfigDebug.PlayerLogging && FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) {
LogWriter.script(String.format("[%s] (Player) %s SAVED LINKED ITEM [%s]", "LINKED ITEM SCRIPTS", player.getCommandSenderName(), linkedItem.getName()));
}
@@ -6,7 +6,6 @@ import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
import kamkeel.npcs.controllers.ProfileController;
import kamkeel.npcs.controllers.SyncController;
import kamkeel.npcs.network.PacketUtil;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.world.WorldServer;
import noppes.npcs.controllers.AuctionController;
@@ -79,8 +78,5 @@ public class ServerTickHandler {
// Save and unload the player's profile data on logout
ProfileController.Instance.logout(event.player);
// Clear script session tokens
PacketUtil.clearScriptSession(event.player);
}
}
@@ -188,11 +188,8 @@ public class TileScripted extends TileEntity implements IScriptBlockHandler, ISc
}
@Override
public void sync(String sessionToken) {
NBTTagCompound compound = getNBT(new NBTTagCompound());
if (sessionToken != null && !sessionToken.isEmpty())
compound.setString("ScriptSessionToken", sessionToken);
sendSavePacket(-1, getScripts().size(), compound);
public void sync() {
sendSavePacket(-1, getScripts().size(), getNBT(new NBTTagCompound()));
}
@Override
@@ -193,8 +193,6 @@ public class ClientTickHandler {
return;
if (mc.theWorld.getTotalWorldTime() % 20 == 0) { // Update every second
if (RequestProperSpawnData.canDoBatchUpdate())
RequestProperSpawnData.handleBacklog();
updateCompassMarks();
}
}
@@ -343,8 +343,6 @@ public class GuiScript extends GuiScriptInterface {
@Override
public void setGuiData(NBTTagCompound compound) {
script.readFromNBT(compound);
if (compound.hasKey("ScriptSessionToken"))
scriptSessionToken = compound.getString("ScriptSessionToken");
loadLanguagesData(compound);
loaded = true;
}
@@ -353,10 +351,7 @@ public class GuiScript extends GuiScriptInterface {
public void save() {
if (loaded) {
setScript();
NBTTagCompound compound = script.writeToNBT(new NBTTagCompound());
if (scriptSessionToken != null)
compound.setString("ScriptSessionToken", scriptSessionToken);
NPCScriptPacket.Save(compound);
NPCScriptPacket.Save(script.writeToNBT(new NBTTagCompound()));
}
}
@@ -49,9 +49,8 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
public Map<String, List<String>> languages = new HashMap();
protected int scriptLimit = 1;
public List<String> hookList = new ArrayList<String>();
protected volatile boolean loaded = false;
protected boolean loaded = false;
protected boolean serverDataReceived = false;
protected String scriptSessionToken = null;
protected Map<Integer, GuiScriptTextArea> textAreas = new HashMap<>();
protected GuiScreen parent;
@@ -756,8 +755,6 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
return;
}
if (result.kind == IScriptHandlerPacket.GuiDataKind.METADATA) {
if (compound.hasKey("ScriptSessionToken"))
scriptSessionToken = compound.getString("ScriptSessionToken");
loadLanguagesData(compound);
return;
}
@@ -768,8 +765,6 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
return;
}
if (compound.hasKey("ScriptSessionToken"))
scriptSessionToken = compound.getString("ScriptSessionToken");
loadLanguagesData(compound);
}
@@ -819,7 +814,9 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
this.setScript();
if (handler instanceof IScriptHandlerPacket)
((IScriptHandlerPacket) handler).sync(scriptSessionToken);
((IScriptHandlerPacket) handler).sync();
}
public void textUpdate(String text) {
@@ -71,29 +71,16 @@ public interface IScriptHandlerPacket extends IScriptHandler {
* GuiScriptInterface is responsible for updating the active {@link IScriptUnit} with current editor text first.
*/
default void sync() {
sync(null);
}
/**
* Emit save packets with a session token for server-side verification.
* The token prevents saving unloaded default data due to race conditions.
*/
default void sync(String sessionToken) {
List<IScriptUnit> containers = getScripts();
for (int i = 0; i < containers.size(); i++) {
IScriptUnit container = containers.get(i);
NBTTagCompound nbt = container.writeToNBT(new NBTTagCompound());
if (sessionToken != null && !sessionToken.isEmpty())
nbt.setString("ScriptSessionToken", sessionToken);
sendSavePacket(i, containers.size(), nbt);
sendSavePacket(i, containers.size(), container.writeToNBT(new NBTTagCompound()));
}
NBTTagCompound scriptData = new NBTTagCompound();
scriptData.setString("ScriptLanguage", getLanguage());
scriptData.setBoolean("ScriptEnabled", getEnabled());
scriptData.setTag("ScriptConsole", NBTTags.NBTLongStringMap(getConsoleText()));
if (sessionToken != null && !sessionToken.isEmpty())
scriptData.setString("ScriptSessionToken", sessionToken);
sendSavePacket(-1, containers.size(), scriptData);
}
}
@@ -2,9 +2,7 @@ package noppes.npcs.controllers.data;
import cpw.mods.fml.common.eventhandler.Event;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.network.PacketUtil;
import kamkeel.npcs.util.ByteBufUtils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.util.Constants;
import noppes.npcs.CustomNpcs;
@@ -119,16 +117,9 @@ public abstract class SingleScriptHandler extends ScriptHandler {
* - tab == 0: Script content NBT follows
* - tab != 0 (typically -1): Script metadata (language, enabled) follows
*/
public boolean saveScript(ByteBuf buffer, EntityPlayer player) throws IOException {
public void saveScript(ByteBuf buffer) throws IOException {
int tab = buffer.readInt();
int totalScripts = buffer.readInt();
NBTTagCompound compound = ByteBufUtils.readNBT(buffer);
// Verify session token
String token = compound.getString("ScriptSessionToken");
if (!PacketUtil.verifyScriptSession(player, token)) {
return false;
}
if (totalScripts == 0) {
this.container = null;
@@ -136,14 +127,15 @@ public abstract class SingleScriptHandler extends ScriptHandler {
if (tab == 0) {
// Script content
this.container = IScriptUnit.createFromNBT(compound, this);
NBTTagCompound tabCompound = ByteBufUtils.readNBT(buffer);
this.container = IScriptUnit.createFromNBT(tabCompound, this);
} else {
// Metadata (language, enabled)
NBTTagCompound compound = ByteBufUtils.readNBT(buffer);
this.setLanguage(compound.getString("ScriptLanguage"));
normalizeLanguage();
this.setEnabled(compound.getBoolean("ScriptEnabled"));
}
return true;
}
/**
@@ -236,6 +236,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti
// For Client-Side Use Only
public int clientFixAttempts = 0;
public long clientFixLastRequestMillis = 0L;
public EntityNPCInterface(World world) {
super(world);
@@ -483,7 +484,14 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti
}
if (wasKilled != isKilled() && wasKilled) {
reset();
if (!worldObj.isRemote) {
reset();
} else {
// Client-side full reset can create health oscillation when spawn data is being repaired.
deathTime = 0;
currentAnimation = EnumAnimation.NONE;
updateHitbox();
}
}
wasKilled = isKilled();
@@ -1838,6 +1846,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti
NBTTagCompound compound = new NBTTagCompound();
display.writeToNBT(compound);
compound.setDouble("MaxHealth", stats.maxHealth);
compound.setFloat("CurrentHealth", getHealth());
compound.setTag("Armor", NBTTags.nbtItemStackList(inventory.getArmor()));
compound.setTag("Weapons", NBTTags.nbtItemStackList(inventory.getWeapons()));
compound.setInteger("Speed", ais.getWalkingSpeed());
@@ -1892,6 +1901,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti
return;
}
float preservedHealth = getHealth();
stats.maxHealth = compound.getDouble("MaxHealth");
ais.setWalkingSpeed(compound.getInteger("Speed"));
stats.hideKilledBody = compound.getBoolean("DeadBody");
@@ -1916,6 +1926,12 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti
ais.bodyOffsetY = compound.getFloat("OffsetY");
this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(stats.maxHealth);
if (compound.hasKey("CurrentHealth", Constants.NBT.TAG_FLOAT)) {
setHealth(MathHelper.clamp_float(compound.getFloat("CurrentHealth"), 0.0F, getMaxHealth()));
} else {
// Keep previous client health if packet came from an older sender format.
setHealth(MathHelper.clamp_float(preservedHealth, 0.0F, getMaxHealth()));
}
inventory.setArmor(NBTTags.getItemStackList(compound.getTagList("Armor", 10)));
inventory.setWeapons(NBTTags.getItemStackList(compound.getTagList("Weapons", 10)));
advanced.setRole(compound.getInteger("Role"));
@@ -1990,6 +2006,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti
return true;
}
clientFixAttempts = 0;
clientFixLastRequestMillis = 0L;
return false;
}
@@ -99,11 +99,8 @@ public class ScriptCustomItem extends ScriptCustomizableItem implements IItemCus
}
@Override
public void sync(String sessionToken) {
NBTTagCompound compound = getMCNbt();
if (sessionToken != null && !sessionToken.isEmpty())
compound.setString("ScriptSessionToken", sessionToken);
sendSavePacket(-1, getScripts().size(), compound);
public void sync() {
sendSavePacket(-1, getScripts().size(), getMCNbt());
}
public int getType() {