
Originally Posted by
Kris
> (ex: "hitpoints" variable in the Entity class)
One of the flaws in matrix; No idea why they didn't just make current hitpoints and prayer be represented as the level value in Skills class. Would be a nicer way of doing it IMO.
Alternatively, if something is directly represented by varp, there is no need to create variables in player/entity class, instead create a method that gets/sets values in the varps directly, remove the excess variable. It's unnecessary.
Given you already have a source written and whatnot, I think defining each existing varp to be saved or not is a bit of a hassle. Instead, I think you should save all the varps whose value isn't a 0 in a map. There is no need to save varbits individually - varbit values are calculated out of the parent varps themselves - you'd naturally have that. However, I would personally add support for defining varps that shouldn't be saved. There are some temporary varps used in RS, you probably wouldn't want their value to carry over between sessions.
As for the other types, I don't really remember much about them so I won't answer on their behalf.
Thanks for the tips on hitpoints/prayers, kind of overlooked that haha

Originally Posted by
Dread
Afaik:
"Config" = Varp
"Config by file?" = Varbit
Global Config = Varc
Global Config String = VarcStr
I think you should just refactor this and remove it, as it's really not needed, as Kris stated Hitpoints/Prayer should just be sent as a stat like the rest of them.
Right now I've got all varps transmitting to the client when their value is changed as a default state and non-zero varps are serialized, but I've added support for overriding those flags via a YAML config (which is also used by the cache tool to create new varbits). The gradle project reads these YAML files at build time and generates code that the server can use to lookup these flags (so that I don't need to write them into the cache, or externally load any other files):

Thanks, I ended up going for this based on your last comment. Basically, I don't serialize nor send varps/varbs by default. I have 2 DBs (one for varps, one for varbs) to specify if I want to do nothing, serialize or serialize&send the varp/varb. Added optional description too after Kris's suggestion. Might change it in the future if I see that they are saved more often than not though.
Code:
package com.rs.game.player.scripts;
import com.common.cache.reader.loaders.ConfigDefinitions;
import com.common.json.JsonFileLoader;
import com.rs.json.VarbsDb;
import com.rs.json.VarpsDb;
import com.rs.net.game.out.game.VarpPacket;
import java.util.HashMap;
import java.util.Map;
/**
* Created by clem585 on 2021-02-14.
*/
public class VarsManager extends PlayerScript {
private transient Map<Integer, Integer> varps;
private transient Map<Integer, Integer> globalInts;
private transient Map<Integer, String> globalStrings;
private Map<Integer, Integer> persistentVarps;
public VarsManager() {
varps = new HashMap<>();
globalInts = new HashMap<>();
globalStrings = new HashMap<>();
persistentVarps = new HashMap<>();
}
@Override
public void init() {
for (int id : JsonFileLoader.get(VarpsDb.class).fetchLoginVarps()) {
if (getVarp(id) != 0) {
player.getEncoder().write(new VarpPacket(id, getVarp(id)));
}
}
for (int id : JsonFileLoader.get(VarbsDb.class).fetchLoginVarbs()) {
if (getVarb(id) != 0) {
// TODO varb packet
// player.getEncoder().write(new ConfigByFilePacket(id, getVarb(id)));
}
}
}
public int getVarp(int id) {
Map<Integer, Integer> configs = JsonFileLoader.get(VarpsDb.class).isPersistent(id) ? persistentVarps : varps;
return configs.getOrDefault(id, 0);
}
public int getVarb(int id) {
ConfigDefinitions configDefinitions = ConfigDefinitions.getConfigDefinitions(id);
Map<Integer, Integer> configs = JsonFileLoader.get(VarbsDb.class).isPersistent(id) ? persistentVarps : varps;
return (configs.getOrDefault(configDefinitions.getConfigId(), 0) & getMask(id))
>> configDefinitions.getStartBit();
}
public int getGlobalInt(int id) {
return globalInts.getOrDefault(id, 0);
}
public String getGlobalString(int id) {
return globalStrings.getOrDefault(id, "");
}
public void setVarp(int id, int value) {
Map<Integer, Integer> configs = JsonFileLoader.get(VarpsDb.class).isPersistent(id) ? persistentVarps : varps;
configs.put(id, value);
}
public void setVarb(int id, int value) {
ConfigDefinitions configDefinitions = ConfigDefinitions.getConfigDefinitions(id);
int max = (int) Math.pow(2, configDefinitions.getEndBit() - configDefinitions.getStartBit());
if (value >= max) {
throw new RuntimeException(String.format("Attempted to overflow varbit, max: %d, value: %d", max, value));
}
value <<= configDefinitions.getStartBit();
Map<Integer, Integer> configs = JsonFileLoader.get(VarbsDb.class).isPersistent(id) ? persistentVarps : varps;
configs.put(configDefinitions.getConfigId(), varps.getOrDefault(configDefinitions.getConfigId(), 0)
& ~getMask(id) | value);
}
public void setGlobalInt(int id, int value) {
globalInts.put(id, value);
}
public void setGlobalString(int id, String value) {
globalStrings.put(id, value);
}
private int getMask(int id) {
ConfigDefinitions configDefinitions = ConfigDefinitions.getConfigDefinitions(id);
int mask = 0;
for (int i = configDefinitions.getStartBit(); i <= configDefinitions.getEndBit(); ++i) {
mask |= (int)Math.pow(2, i);
}
return mask;
}
}
Code:
package com.rs.json.models;
/**
* Created by clem585 on 2021-02-14.
*/
public enum VarStatus {
NORMAL, PERSISTENT, SEND_ON_LOGIN
}
Code:
package com.rs.json.models;
import lombok.Getter;
import lombok.Setter;
/**
* Created by clem585 on 2021-02-14.
*/
public class VarDetails {
@Getter @Setter
private String description;
@Getter @Setter
private VarStatus varStatus;
public VarDetails() {
varStatus = VarStatus.NORMAL;
}
}
Code:
package com.rs.json;
import com.common.json.JsonFile;
import com.fasterxml.jackson.core.type.TypeReference;
import com.rs.json.models.VarDetails;
import com.rs.json.models.VarStatus;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Created by clem585 on 2021-02-14.
*/
public class VarbsDb extends JsonFile<Map<Integer, VarDetails>> {
public VarbsDb() {
super("varbs");
}
public void setStatus(int id, VarStatus status) {
VarDetails details = data.getOrDefault(id, new VarDetails());
if (status == VarStatus.NORMAL && details.getDescription() == null) {
data.remove(id);
} else {
details.setVarStatus(status);
data.put(id, details);
}
}
public void setDescription(int id, String description) {
VarDetails details = data.getOrDefault(id, new VarDetails());
details.setDescription(description);
data.put(id, details);
}
public boolean isPersistent(int id) {
return data.containsKey(id) && data.get(id).getVarStatus() != VarStatus.NORMAL;
}
public List<Integer> fetchLoginVarbs() {
return data.keySet().stream().filter((key) -> data.get(key).getVarStatus() == VarStatus.SEND_ON_LOGIN).
collect(Collectors.toList());
}
@Override
protected Class getValueType() {
return HashMap.class;
}
@Override
protected TypeReference getTypeReference() {
return new TypeReference<HashMap<Integer, VarDetails>>(){};
}
}

Originally Posted by
Displee
You only store varps. You don't store varcs (global configs) or stringcs (global strings). It's also not possible to maintain varcs or stringcs since they get manipulated by cs2. There's also a very small amount of varps that get manipulated by cs2.
Thanks, I didn't know much about varcs and stringcs since I only used them a few times in the past. In that case would it be better to not save them at all in the VarpManager since they're usually only sent once and then accessed client-sided?